sls/tests/Feature/CandidateInterviewPortalTest.php
2026-07-20 21:50:30 +05:30

164 lines
5.6 KiB
PHP

<?php
namespace Tests\Feature;
use App\Models\Interview;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Http;
use Tests\TestCase;
class CandidateInterviewPortalTest extends TestCase
{
use RefreshDatabase;
protected function setUp(): void
{
parent::setUp();
$this->withoutMiddleware();
}
public function test_hr_can_create_candidate_interview_and_generate_temp_credentials(): void
{
$hr = User::create([
'name' => 'HR Manager',
'email' => 'hr@company.com',
'role' => 'user',
]);
$response = $this->actingAs($hr)
->post(route('interview.store'), [
'candidate_name' => 'Alex Candidate',
'candidate_email' => 'alex.cand@gmail.com',
'candidate_phone' => '9876543210',
'valid_hours' => 2,
'language' => 'python',
]);
$response->assertRedirect(route('interview.index'));
$this->assertDatabaseHas('interviews', [
'candidate_name' => 'Alex Candidate',
'candidate_email' => 'alex.cand@gmail.com',
'candidate_phone' => '9876543210',
'status' => 'scheduled',
]);
}
public function test_candidate_can_login_with_temp_credentials_and_access_ide_room(): void
{
$interview = Interview::create([
'candidate_name' => 'Sarah Candidate',
'candidate_email' => 'sarah@gmail.com',
'candidate_phone' => '9123456789',
'temp_password' => 'Pass-123456',
'expires_at' => now()->addHours(2),
'language' => 'cpp',
'status' => 'scheduled',
'submission_unique_id' => 'sarah-candidate_9123456789_1752000000',
]);
$response = $this->post(route('interview.candidate.login.submit'), [
'identifier' => 'sarah@gmail.com',
'temp_password' => 'Pass-123456',
]);
$response->assertRedirect(route('interview.room', $interview->submission_unique_id));
$this->get(route('interview.room', $interview->submission_unique_id))
->assertStatus(200)
->assertSee('Sarah Candidate')
->assertSee('sarah-candidate_9123456789_1752000000');
}
public function test_live_code_execution_via_piston_api_proxy(): void
{
Http::fake([
'https://emkc.org/api/v2/piston/execute' => Http::response([
'run' => [
'output' => "Hello from SingleLogin Assessment!\nComputed Result: 84\n"
]
], 200)
]);
$response = $this->post(route('interview.execute'), [
'language' => 'python',
'code' => 'print("Hello from SingleLogin Assessment!")',
]);
$response->assertStatus(200)
->assertJson([
'success' => true,
'output' => "Hello from SingleLogin Assessment!\nComputed Result: 84\n"
]);
}
public function test_candidate_code_submission_saves_under_unique_submission_id(): void
{
$interview = Interview::create([
'candidate_name' => 'Michael Dev',
'candidate_email' => 'michael@gmail.com',
'candidate_phone' => '9988776655',
'temp_password' => 'Pass-654321',
'expires_at' => now()->addHours(2),
'language' => 'php',
'status' => 'in_progress',
'submission_unique_id' => 'michael-dev_9988776655_1752000001',
]);
$response = $this->post(route('interview.submit', $interview->id), [
'code' => '<?php echo "Solution completed";',
'language' => 'php',
'output' => 'Solution completed',
]);
$response->assertStatus(200)
->assertJson([
'success' => true,
'unique_id' => 'michael-dev_9988776655_1752000001'
]);
$interview->refresh();
$this->assertEquals('completed', $interview->status);
$this->assertEquals('<?php echo "Solution completed";', $interview->submitted_code);
}
public function test_proctoring_violation_logging_and_silent_warning(): void
{
$hr = User::create([
'name' => 'Interviewer HR',
'email' => 'hrpanel@company.com',
'role' => 'admin',
]);
$interview = Interview::create([
'candidate_name' => 'Test Candidate',
'candidate_email' => 'test@gmail.com',
'candidate_phone' => '9111111111',
'temp_password' => 'Pass-111111',
'expires_at' => now()->addHours(2),
'language' => 'python',
'status' => 'in_progress',
'submission_unique_id' => 'test-candidate_9111111111_1752000002',
]);
// Log tab switch violation
$this->post(route('interview.violation', $interview->id), [
'type' => 'tab_switch',
'details' => 'Candidate switched tab',
])->assertStatus(200);
// Send silent warning from HR
$this->actingAs($hr)
->post(route('interview.warning', $interview->id), [
'message' => 'Please stay on the test tab.',
])->assertStatus(200);
// Verify poll endpoint returns violation and warning
$pollResponse = $this->get(route('interview.poll', $interview->id));
$pollResponse->assertStatus(200)
->assertJsonFragment(['type' => 'tab_switch'])
->assertJsonFragment(['message' => 'Please stay on the test tab.']);
}
}