add all controllers logic
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\V1\Attendance;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Tests\TestCase;
|
||||
|
||||
class LateSlipLogsControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_index_requires_admin(): void
|
||||
{
|
||||
$user = $this->createUser('teacher');
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->getJson('/api/v1/attendance/late-slip-logs');
|
||||
|
||||
$response->assertForbidden();
|
||||
}
|
||||
|
||||
public function test_index_returns_logs(): void
|
||||
{
|
||||
$admin = $this->createUser('admin');
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
DB::table('late_slip_logs')->insert([
|
||||
'school_year' => '2025-2026',
|
||||
'semester' => 'Fall',
|
||||
'student_name' => 'Student One',
|
||||
'slip_date' => '2025-09-01',
|
||||
'time_in' => '08:10:00',
|
||||
'grade' => '3',
|
||||
'reason' => 'Traffic',
|
||||
'admin_name' => 'Admin User',
|
||||
]);
|
||||
|
||||
$response = $this->getJson('/api/v1/attendance/late-slip-logs?school_year=2025-2026');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('data.logs.0.student_name', 'Student One');
|
||||
$response->assertJsonStructure(['data' => ['meta']]);
|
||||
}
|
||||
|
||||
public function test_show_returns_log(): void
|
||||
{
|
||||
$admin = $this->createUser('admin');
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
DB::table('late_slip_logs')->insert([
|
||||
'school_year' => '2025-2026',
|
||||
'semester' => 'Fall',
|
||||
'student_name' => 'Student Two',
|
||||
'slip_date' => '2025-09-02',
|
||||
'time_in' => '08:15:00',
|
||||
'grade' => '2',
|
||||
'reason' => 'Bus delay',
|
||||
'admin_name' => 'Admin User',
|
||||
]);
|
||||
|
||||
$response = $this->getJson('/api/v1/attendance/late-slip-logs/1');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('data.log.student_name', 'Student Two');
|
||||
}
|
||||
|
||||
public function test_destroy_deletes_log(): void
|
||||
{
|
||||
$admin = $this->createUser('admin');
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
DB::table('late_slip_logs')->insert([
|
||||
'school_year' => '2025-2026',
|
||||
'semester' => 'Fall',
|
||||
'student_name' => 'Student Three',
|
||||
'slip_date' => '2025-09-03',
|
||||
'time_in' => '08:20:00',
|
||||
'grade' => '1',
|
||||
'reason' => 'Weather',
|
||||
'admin_name' => 'Admin User',
|
||||
]);
|
||||
|
||||
$response = $this->deleteJson('/api/v1/attendance/late-slip-logs/1');
|
||||
|
||||
$response->assertOk();
|
||||
$this->assertDatabaseMissing('late_slip_logs', [
|
||||
'id' => 1,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_index_validation_rejects_bad_dates(): void
|
||||
{
|
||||
$admin = $this->createUser('admin');
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
$response = $this->getJson('/api/v1/attendance/late-slip-logs?date_from=not-a-date');
|
||||
|
||||
$response->assertStatus(422);
|
||||
$response->assertJsonStructure(['message', 'errors']);
|
||||
}
|
||||
|
||||
private function createUser(string $roleName): User
|
||||
{
|
||||
$roleId = DB::table('roles')->insertGetId([
|
||||
'name' => $roleName,
|
||||
'priority' => 1,
|
||||
'is_active' => 1,
|
||||
]);
|
||||
|
||||
$user = User::query()->create([
|
||||
'firstname' => 'Test',
|
||||
'lastname' => 'User',
|
||||
'email' => $roleName . '@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
DB::table('user_roles')->insert([
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $roleId,
|
||||
]);
|
||||
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\V1\Auth;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Tests\TestCase;
|
||||
|
||||
class IpBanControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_index_requires_admin(): void
|
||||
{
|
||||
$user = $this->createUser('teacher');
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->getJson('/api/v1/ip-bans');
|
||||
|
||||
$response->assertForbidden();
|
||||
}
|
||||
|
||||
public function test_index_returns_bans(): void
|
||||
{
|
||||
$admin = $this->createUser('admin');
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
DB::table('ip_attempts')->insert([
|
||||
'ip_address' => '10.0.0.1',
|
||||
'attempts' => 5,
|
||||
'blocked_until' => now('UTC')->addHours(2),
|
||||
]);
|
||||
|
||||
$response = $this->getJson('/api/v1/ip-bans?status=active');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('data.bans.0.ip_address', '10.0.0.1');
|
||||
$response->assertJsonStructure(['data' => ['meta']]);
|
||||
}
|
||||
|
||||
public function test_show_returns_ban(): void
|
||||
{
|
||||
$admin = $this->createUser('admin');
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
DB::table('ip_attempts')->insert([
|
||||
'ip_address' => '10.0.0.2',
|
||||
'attempts' => 3,
|
||||
'blocked_until' => now('UTC')->addHours(1),
|
||||
]);
|
||||
|
||||
$response = $this->getJson('/api/v1/ip-bans/1');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('data.ban.ip_address', '10.0.0.2');
|
||||
}
|
||||
|
||||
public function test_ban_creates_block(): void
|
||||
{
|
||||
$admin = $this->createUser('admin');
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
DB::table('ip_attempts')->insert([
|
||||
'ip_address' => '10.0.0.3',
|
||||
'attempts' => 1,
|
||||
]);
|
||||
|
||||
$response = $this->postJson('/api/v1/ip-bans/ban', [
|
||||
'ip' => '10.0.0.3',
|
||||
'hours' => 12,
|
||||
]);
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('data.ban.ip_address', '10.0.0.3');
|
||||
$this->assertDatabaseHas('ip_attempts', [
|
||||
'ip_address' => '10.0.0.3',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_unban_single(): void
|
||||
{
|
||||
$admin = $this->createUser('admin');
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
DB::table('ip_attempts')->insert([
|
||||
'ip_address' => '10.0.0.4',
|
||||
'attempts' => 5,
|
||||
'blocked_until' => now('UTC')->addHours(2),
|
||||
]);
|
||||
|
||||
$response = $this->postJson('/api/v1/ip-bans/unban', [
|
||||
'ip' => '10.0.0.4',
|
||||
]);
|
||||
|
||||
$response->assertOk();
|
||||
$this->assertDatabaseHas('ip_attempts', [
|
||||
'ip_address' => '10.0.0.4',
|
||||
'blocked_until' => null,
|
||||
'attempts' => 0,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_unban_all(): void
|
||||
{
|
||||
$admin = $this->createUser('admin');
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
DB::table('ip_attempts')->insert([
|
||||
[
|
||||
'ip_address' => '10.0.0.5',
|
||||
'attempts' => 5,
|
||||
'blocked_until' => now('UTC')->addHours(2),
|
||||
],
|
||||
[
|
||||
'ip_address' => '10.0.0.6',
|
||||
'attempts' => 2,
|
||||
'blocked_until' => now('UTC')->addHours(2),
|
||||
],
|
||||
]);
|
||||
|
||||
$response = $this->postJson('/api/v1/ip-bans/unban', [
|
||||
'all' => true,
|
||||
]);
|
||||
|
||||
$response->assertOk();
|
||||
$this->assertDatabaseHas('ip_attempts', [
|
||||
'ip_address' => '10.0.0.5',
|
||||
'blocked_until' => null,
|
||||
]);
|
||||
$this->assertDatabaseHas('ip_attempts', [
|
||||
'ip_address' => '10.0.0.6',
|
||||
'blocked_until' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_ban_validation_requires_ip_or_id(): void
|
||||
{
|
||||
$admin = $this->createUser('admin');
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
$response = $this->postJson('/api/v1/ip-bans/ban', [
|
||||
'hours' => 12,
|
||||
]);
|
||||
|
||||
$response->assertStatus(422);
|
||||
$response->assertJsonStructure(['message', 'errors']);
|
||||
}
|
||||
|
||||
private function createUser(string $roleName): User
|
||||
{
|
||||
$roleId = DB::table('roles')->insertGetId([
|
||||
'name' => $roleName,
|
||||
'priority' => 1,
|
||||
'is_active' => 1,
|
||||
]);
|
||||
|
||||
$user = User::query()->create([
|
||||
'firstname' => 'Test',
|
||||
'lastname' => 'User',
|
||||
'email' => $roleName . '@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
DB::table('user_roles')->insert([
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $roleId,
|
||||
]);
|
||||
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,8 @@ class RegisterControllerTest extends TestCase
|
||||
'is_active' => 1,
|
||||
]);
|
||||
|
||||
$captcha = $this->getJson('/api/v1/auth/register/captcha')->json('captcha');
|
||||
|
||||
$payload = [
|
||||
'firstname' => 'Parent',
|
||||
'lastname' => 'User',
|
||||
@@ -52,13 +54,12 @@ class RegisterControllerTest extends TestCase
|
||||
'state' => 'CT',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'captcha' => 'ABCD',
|
||||
'captcha' => $captcha,
|
||||
'is_parent' => 1,
|
||||
'no_second_parent_info' => 1,
|
||||
];
|
||||
|
||||
$response = $this->withSession(['captcha_answer' => 'ABCD'])
|
||||
->postJson('/api/v1/auth/register', $payload);
|
||||
$response = $this->postJson('/api/v1/auth/register', $payload);
|
||||
|
||||
$response->assertCreated();
|
||||
$response->assertJsonPath('ok', true);
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\V1\Auth;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Tests\TestCase;
|
||||
|
||||
class SessionTimeoutControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_config_returns_timeout_values(): void
|
||||
{
|
||||
$user = $this->seedUser();
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->getJson('/api/v1/session/timeout-config');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('status', true);
|
||||
$this->assertArrayHasKey('timeout', $response->json('data.config'));
|
||||
$this->assertArrayHasKey('keep_alive_url', $response->json('data.config'));
|
||||
}
|
||||
|
||||
public function test_check_timeout_returns_active_status(): void
|
||||
{
|
||||
$user = $this->seedUser();
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this
|
||||
->withSession(['last_activity' => time() - 10])
|
||||
->getJson('/api/v1/session/check-timeout');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('status', true);
|
||||
$response->assertJsonPath('data.session.status', 'active');
|
||||
}
|
||||
|
||||
public function test_check_timeout_returns_warning_status(): void
|
||||
{
|
||||
$user = $this->seedUser();
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this
|
||||
->withSession(['last_activity' => time() - 1000])
|
||||
->getJson('/api/v1/session/check-timeout');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('status', true);
|
||||
$response->assertJsonPath('data.session.status', 'warning');
|
||||
}
|
||||
|
||||
public function test_check_timeout_returns_expired_status(): void
|
||||
{
|
||||
$user = $this->seedUser();
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this
|
||||
->withSession(['last_activity' => time() - 5000])
|
||||
->getJson('/api/v1/session/check-timeout');
|
||||
|
||||
$response->assertStatus(401);
|
||||
$response->assertJsonPath('status', false);
|
||||
$response->assertJsonPath('errors.status', 'expired');
|
||||
}
|
||||
|
||||
public function test_ping_updates_activity(): void
|
||||
{
|
||||
$user = $this->seedUser();
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this
|
||||
->withSession(['last_activity' => time() - 10])
|
||||
->postJson('/api/v1/session/ping');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('status', true);
|
||||
$response->assertJsonPath('data.session.status', 'active');
|
||||
}
|
||||
|
||||
public function test_ping_returns_expired_when_missing_activity(): void
|
||||
{
|
||||
$user = $this->seedUser();
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->postJson('/api/v1/session/ping');
|
||||
|
||||
$response->assertStatus(401);
|
||||
$response->assertJsonPath('status', false);
|
||||
}
|
||||
|
||||
public function test_requires_authentication(): void
|
||||
{
|
||||
$response = $this->getJson('/api/v1/session/timeout-config');
|
||||
|
||||
$response->assertStatus(401);
|
||||
}
|
||||
|
||||
private function seedUser(): User
|
||||
{
|
||||
$userId = DB::table('users')->insertGetId([
|
||||
'firstname' => 'Admin',
|
||||
'lastname' => 'User',
|
||||
'cellphone' => '9999999999',
|
||||
'email' => 'session@example.com',
|
||||
'address_street' => '123 Street',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'password' => bcrypt('password'),
|
||||
'user_type' => 'primary',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
'status' => 'Active',
|
||||
]);
|
||||
|
||||
return User::query()->findOrFail($userId);
|
||||
}
|
||||
}
|
||||
@@ -23,11 +23,14 @@ class ClassPreparationControllerTest extends TestCase
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJson([
|
||||
'ok' => true,
|
||||
'schoolYear' => '2025-2026',
|
||||
'semester' => 'Fall',
|
||||
'status' => true,
|
||||
'message' => 'Success',
|
||||
'data' => [
|
||||
'schoolYear' => '2025-2026',
|
||||
'semester' => 'Fall',
|
||||
],
|
||||
]);
|
||||
$this->assertNotEmpty($response->json('results'));
|
||||
$this->assertNotEmpty($response->json('data.results'));
|
||||
}
|
||||
|
||||
public function test_mark_printed_creates_snapshots(): void
|
||||
@@ -40,12 +43,12 @@ class ClassPreparationControllerTest extends TestCase
|
||||
$response = $this->postJson('/api/v1/class-prep/mark-printed', [
|
||||
'school_year' => '2025-2026',
|
||||
'semester' => 'Fall',
|
||||
'class_section_ids' => [101],
|
||||
'class_section_ids' => ['101'],
|
||||
]);
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJson([
|
||||
'ok' => true,
|
||||
'status' => true,
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('class_preparation_log', [
|
||||
@@ -54,6 +57,66 @@ class ClassPreparationControllerTest extends TestCase
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_mark_printed_rejects_invalid_payload(): void
|
||||
{
|
||||
$user = $this->createUser();
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->postJson('/api/v1/class-prep/mark-printed', [
|
||||
'class_section_ids' => [],
|
||||
]);
|
||||
|
||||
$response->assertStatus(422);
|
||||
$response->assertJsonStructure(['message', 'errors']);
|
||||
}
|
||||
|
||||
public function test_save_adjustments_updates_rows(): void
|
||||
{
|
||||
$this->seedPrepData();
|
||||
|
||||
$user = $this->createUser();
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->postJson('/api/v1/class-prep/adjustments', [
|
||||
'class_section_id' => '101',
|
||||
'school_year' => '2025-2026',
|
||||
'adjustments' => [
|
||||
'Small Table' => 2,
|
||||
],
|
||||
]);
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJson([
|
||||
'status' => true,
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('class_prep_adjustments', [
|
||||
'class_section_id' => '101',
|
||||
'school_year' => '2025-2026',
|
||||
'item_name' => 'Small Table',
|
||||
'adjustment' => 2,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_print_logs_prep_items(): void
|
||||
{
|
||||
$this->seedPrepData();
|
||||
|
||||
$user = $this->createUser();
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->postJson('/api/v1/class-prep/print/101/2025-2026');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('status', true);
|
||||
$response->assertJsonPath('data.print.class_section_id', '101');
|
||||
|
||||
$this->assertDatabaseHas('class_preparation_log', [
|
||||
'class_section_id' => 101,
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
}
|
||||
|
||||
private function seedPrepData(): void
|
||||
{
|
||||
DB::table('configuration')->insert([
|
||||
|
||||
@@ -0,0 +1,282 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\V1\Classes;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ClassSectionControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_index_returns_sections(): void
|
||||
{
|
||||
$user = $this->createUser();
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
DB::table('classes')->insert([
|
||||
'class_name' => 'Class 1',
|
||||
'schedule' => 'Monday',
|
||||
'capacity' => 30,
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
DB::table('classSection')->insert([
|
||||
'class_id' => 1,
|
||||
'class_section_id' => 101,
|
||||
'class_section_name' => '1-A',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$response = $this->getJson('/api/v1/class-sections');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('data.sections.0.class_section_name', '1-A');
|
||||
}
|
||||
|
||||
public function test_store_requires_admin(): void
|
||||
{
|
||||
$user = $this->createUser();
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->postJson('/api/v1/class-sections', [
|
||||
'class_id' => 1,
|
||||
'class_section_id' => 101,
|
||||
'class_section_name' => '1-A',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$response->assertForbidden();
|
||||
}
|
||||
|
||||
public function test_store_creates_class_section(): void
|
||||
{
|
||||
$admin = $this->createUser('admin');
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
DB::table('classes')->insert([
|
||||
'class_name' => 'Class 1',
|
||||
'schedule' => 'Monday',
|
||||
'capacity' => 30,
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$response = $this->postJson('/api/v1/class-sections', [
|
||||
'class_id' => 1,
|
||||
'class_section_id' => 101,
|
||||
'class_section_name' => '1-A',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$response->assertCreated();
|
||||
$this->assertDatabaseHas('classSection', [
|
||||
'class_section_id' => 101,
|
||||
'class_section_name' => '1-A',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_update_requires_admin(): void
|
||||
{
|
||||
DB::table('classSection')->insert([
|
||||
'class_id' => 1,
|
||||
'class_section_id' => 101,
|
||||
'class_section_name' => '1-A',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$user = $this->createUser();
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->putJson('/api/v1/class-sections/1', [
|
||||
'class_section_name' => '1-B',
|
||||
]);
|
||||
|
||||
$response->assertForbidden();
|
||||
}
|
||||
|
||||
public function test_show_returns_section(): void
|
||||
{
|
||||
DB::table('classSection')->insert([
|
||||
'class_id' => 1,
|
||||
'class_section_id' => 101,
|
||||
'class_section_name' => '1-A',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$user = $this->createUser();
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->getJson('/api/v1/class-sections/1');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('data.section.class_section_name', '1-A');
|
||||
}
|
||||
|
||||
public function test_update_modifies_class_section(): void
|
||||
{
|
||||
DB::table('classSection')->insert([
|
||||
'class_id' => 1,
|
||||
'class_section_id' => 101,
|
||||
'class_section_name' => '1-A',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$admin = $this->createUser('admin');
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
$response = $this->putJson('/api/v1/class-sections/1', [
|
||||
'class_section_name' => '1-B',
|
||||
]);
|
||||
|
||||
$response->assertOk();
|
||||
$this->assertDatabaseHas('classSection', [
|
||||
'id' => 1,
|
||||
'class_section_name' => '1-B',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_destroy_deletes_class_section(): void
|
||||
{
|
||||
DB::table('classSection')->insert([
|
||||
'class_id' => 1,
|
||||
'class_section_id' => 101,
|
||||
'class_section_name' => '1-A',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$admin = $this->createUser('admin');
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
$response = $this->deleteJson('/api/v1/class-sections/1');
|
||||
|
||||
$response->assertOk();
|
||||
$this->assertDatabaseMissing('classSection', [
|
||||
'id' => 1,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_attendance_returns_students(): void
|
||||
{
|
||||
DB::table('configuration')->insert([
|
||||
['config_key' => 'school_year', 'config_value' => '2025-2026'],
|
||||
['config_key' => 'semester', 'config_value' => 'Fall'],
|
||||
]);
|
||||
|
||||
DB::table('classSection')->insert([
|
||||
'class_id' => 1,
|
||||
'class_section_id' => 101,
|
||||
'class_section_name' => '1-A',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
DB::table('students')->insert([
|
||||
'school_id' => 'S-1',
|
||||
'firstname' => 'Student',
|
||||
'lastname' => 'One',
|
||||
'age' => 8,
|
||||
'gender' => 'Male',
|
||||
'photo_consent' => 1,
|
||||
'parent_id' => 1,
|
||||
'year_of_registration' => '2025',
|
||||
'school_year' => '2025-2026',
|
||||
'semester' => 'Fall',
|
||||
'is_active' => 1,
|
||||
]);
|
||||
|
||||
DB::table('student_class')->insert([
|
||||
'student_id' => 1,
|
||||
'class_section_id' => 101,
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$teacher = $this->createUser();
|
||||
Sanctum::actingAs($teacher);
|
||||
|
||||
$response = $this->getJson('/api/v1/class-sections/101/attendance');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('data.attendance.class_section_id', 101);
|
||||
$response->assertJsonCount(1, 'data.attendance.students');
|
||||
}
|
||||
|
||||
public function test_seed_defaults_creates_classes(): void
|
||||
{
|
||||
DB::table('configuration')->insert([
|
||||
['config_key' => 'school_year', 'config_value' => '2025-2026'],
|
||||
['config_key' => 'semester', 'config_value' => 'Fall'],
|
||||
]);
|
||||
|
||||
$admin = $this->createUser('admin');
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
$response = $this->postJson('/api/v1/class-sections/seed-defaults');
|
||||
|
||||
$response->assertOk();
|
||||
$this->assertDatabaseHas('classes', [
|
||||
'class_name' => 'Class 1',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_validation_rejects_invalid_payload(): void
|
||||
{
|
||||
$admin = $this->createUser('admin');
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
$response = $this->postJson('/api/v1/class-sections', [
|
||||
'class_id' => 'bad',
|
||||
]);
|
||||
|
||||
$response->assertStatus(422);
|
||||
$response->assertJsonStructure(['message', 'errors']);
|
||||
}
|
||||
|
||||
private function createUser(string $roleName = 'teacher'): User
|
||||
{
|
||||
DB::table('roles')->insert([
|
||||
'id' => 1,
|
||||
'name' => $roleName,
|
||||
'priority' => 1,
|
||||
]);
|
||||
|
||||
DB::table('users')->insert([
|
||||
'school_id' => 1,
|
||||
'firstname' => 'Test',
|
||||
'lastname' => 'User',
|
||||
'cellphone' => '5555555555',
|
||||
'email' => $roleName . '@example.com',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'is_verified' => 1,
|
||||
'status' => 'Active',
|
||||
'is_suspended' => 0,
|
||||
'failed_attempts' => 0,
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
DB::table('user_roles')->insert([
|
||||
'user_id' => 1,
|
||||
'role_id' => 1,
|
||||
]);
|
||||
|
||||
return User::query()->findOrFail(1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\V1\Frontend;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Tests\TestCase;
|
||||
|
||||
class FrontendControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_index_returns_page(): void
|
||||
{
|
||||
$response = $this->getJson('/api/v1/frontend');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('data.page.page', 'index');
|
||||
}
|
||||
|
||||
public function test_fetch_user_requires_auth(): void
|
||||
{
|
||||
$response = $this->getJson('/api/v1/frontend/me');
|
||||
|
||||
$response->assertStatus(401);
|
||||
}
|
||||
|
||||
public function test_fetch_user_returns_profile(): void
|
||||
{
|
||||
$user = $this->createUser('parent');
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->getJson('/api/v1/frontend/me');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('data.user.firstname', 'Test');
|
||||
}
|
||||
|
||||
private function createUser(string $roleName): User
|
||||
{
|
||||
$roleId = DB::table('roles')->insertGetId([
|
||||
'name' => $roleName,
|
||||
'priority' => 1,
|
||||
'is_active' => 1,
|
||||
]);
|
||||
|
||||
$user = User::query()->create([
|
||||
'firstname' => 'Test',
|
||||
'lastname' => 'User',
|
||||
'email' => $roleName . '@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
DB::table('user_roles')->insert([
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $roleId,
|
||||
]);
|
||||
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\V1\Frontend;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Tests\TestCase;
|
||||
|
||||
class InfoIconControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_profile_icon_returns_initials(): void
|
||||
{
|
||||
$user = User::query()->create([
|
||||
'firstname' => 'John',
|
||||
'lastname' => 'Doe',
|
||||
'email' => 'john@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->getJson('/api/v1/info-icon/profile');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('data.profile.user_initials', 'JD');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\V1\Frontend;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Tests\TestCase;
|
||||
|
||||
class LandingPageControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_index_returns_admin_dashboard(): void
|
||||
{
|
||||
$user = $this->createUser('admin');
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->getJson('/api/v1/landing');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('data.landing.role', 'admin');
|
||||
}
|
||||
|
||||
public function test_teacher_dashboard_returns_summary(): void
|
||||
{
|
||||
$user = $this->createUser('teacher');
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->getJson('/api/v1/landing/teacher');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('data.landing.dashboard', 'teacher');
|
||||
$response->assertJsonStructure(['data' => ['landing' => ['summary']]]);
|
||||
}
|
||||
|
||||
public function test_parent_dashboard_returns_summary(): void
|
||||
{
|
||||
$user = $this->createUser('parent');
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->getJson('/api/v1/landing/parent');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('data.landing.dashboard', 'parent');
|
||||
}
|
||||
|
||||
private function createUser(string $roleName): User
|
||||
{
|
||||
$roleId = DB::table('roles')->insertGetId([
|
||||
'name' => $roleName,
|
||||
'priority' => 1,
|
||||
'is_active' => 1,
|
||||
]);
|
||||
|
||||
$user = User::query()->create([
|
||||
'firstname' => 'Test',
|
||||
'lastname' => 'User',
|
||||
'email' => $roleName . '@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
'user_type' => 'primary',
|
||||
]);
|
||||
|
||||
DB::table('user_roles')->insert([
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $roleId,
|
||||
]);
|
||||
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\V1\Frontend;
|
||||
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Tests\TestCase;
|
||||
|
||||
class PageControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_privacy_returns_content(): void
|
||||
{
|
||||
$dir = public_path('html');
|
||||
File::ensureDirectoryExists($dir);
|
||||
File::put($dir . '/privacy_policy.html', '<h1>Privacy</h1>');
|
||||
|
||||
$response = $this->getJson('/api/v1/pages/privacy');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('data.page.type', 'privacy_policy');
|
||||
$this->assertStringContainsString('Privacy', $response->json('data.page.content'));
|
||||
}
|
||||
|
||||
public function test_help_missing_returns_error(): void
|
||||
{
|
||||
$dir = public_path('html');
|
||||
File::ensureDirectoryExists($dir);
|
||||
File::delete($dir . '/help_center.html');
|
||||
|
||||
$response = $this->getJson('/api/v1/pages/help');
|
||||
|
||||
$response->assertStatus(404);
|
||||
}
|
||||
|
||||
public function test_submit_contact_persists(): void
|
||||
{
|
||||
DB::table('configuration')->insert([
|
||||
['config_key' => 'school_year', 'config_value' => '2025-2026'],
|
||||
['config_key' => 'semester', 'config_value' => 'Fall'],
|
||||
]);
|
||||
|
||||
$payload = [
|
||||
'email' => 'contact@example.com',
|
||||
'message' => 'Hello there, this is a test message.',
|
||||
];
|
||||
|
||||
$response = $this->postJson('/api/v1/pages/contact', $payload);
|
||||
|
||||
$response->assertStatus(201);
|
||||
$this->assertDatabaseHas('contactus', [
|
||||
'subject' => 'Contact Us Form Submission',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\V1\Messaging;
|
||||
|
||||
use App\Models\Message;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Tests\TestCase;
|
||||
|
||||
class MessagesControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_inbox_requires_auth(): void
|
||||
{
|
||||
$response = $this->getJson('/api/v1/messages/inbox');
|
||||
|
||||
$response->assertStatus(401);
|
||||
}
|
||||
|
||||
public function test_store_creates_message(): void
|
||||
{
|
||||
DB::table('configuration')->insert([
|
||||
['config_key' => 'school_year', 'config_value' => '2025-2026'],
|
||||
['config_key' => 'semester', 'config_value' => 'Fall'],
|
||||
]);
|
||||
|
||||
$sender = $this->createUser('parent', 'sender@example.com');
|
||||
$recipient = $this->createUser('teacher', 'recipient@example.com');
|
||||
Sanctum::actingAs($sender);
|
||||
|
||||
$payload = [
|
||||
'recipient_id' => $recipient->id,
|
||||
'subject' => 'Hello',
|
||||
'message' => 'Test message',
|
||||
];
|
||||
|
||||
$response = $this->postJson('/api/v1/messages', $payload);
|
||||
|
||||
$response->assertStatus(201);
|
||||
$this->assertDatabaseHas('messages', [
|
||||
'sender_id' => $sender->id,
|
||||
'recipient_id' => $recipient->id,
|
||||
'subject' => 'Hello',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_show_marks_read(): void
|
||||
{
|
||||
$sender = $this->createUser('parent', 'sender2@example.com');
|
||||
$recipient = $this->createUser('teacher', 'recipient2@example.com');
|
||||
|
||||
$message = Message::query()->create([
|
||||
'sender_id' => $sender->id,
|
||||
'recipient_id' => $recipient->id,
|
||||
'subject' => 'Subject',
|
||||
'message' => 'Body',
|
||||
'sent_datetime' => now(),
|
||||
'read_status' => 0,
|
||||
'message_number' => 'MSG-123',
|
||||
'priority' => 'normal',
|
||||
'status' => 'sent',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
Sanctum::actingAs($recipient);
|
||||
|
||||
$response = $this->getJson('/api/v1/messages/' . $message->id);
|
||||
|
||||
$response->assertOk();
|
||||
$this->assertDatabaseHas('messages', [
|
||||
'id' => $message->id,
|
||||
'read_status' => 1,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_update_changes_status(): void
|
||||
{
|
||||
$sender = $this->createUser('parent', 'sender3@example.com');
|
||||
$recipient = $this->createUser('teacher', 'recipient3@example.com');
|
||||
|
||||
$message = Message::query()->create([
|
||||
'sender_id' => $sender->id,
|
||||
'recipient_id' => $recipient->id,
|
||||
'subject' => 'Subject',
|
||||
'message' => 'Body',
|
||||
'sent_datetime' => now(),
|
||||
'read_status' => 0,
|
||||
'message_number' => 'MSG-124',
|
||||
'priority' => 'normal',
|
||||
'status' => 'sent',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
Sanctum::actingAs($sender);
|
||||
|
||||
$response = $this->patchJson('/api/v1/messages/' . $message->id, [
|
||||
'status' => 'trashed',
|
||||
]);
|
||||
|
||||
$response->assertOk();
|
||||
$this->assertDatabaseHas('messages', [
|
||||
'id' => $message->id,
|
||||
'status' => 'trashed',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_destroy_marks_trashed(): void
|
||||
{
|
||||
$sender = $this->createUser('parent', 'sender4@example.com');
|
||||
$recipient = $this->createUser('teacher', 'recipient4@example.com');
|
||||
|
||||
$message = Message::query()->create([
|
||||
'sender_id' => $sender->id,
|
||||
'recipient_id' => $recipient->id,
|
||||
'subject' => 'Subject',
|
||||
'message' => 'Body',
|
||||
'sent_datetime' => now(),
|
||||
'read_status' => 0,
|
||||
'message_number' => 'MSG-125',
|
||||
'priority' => 'normal',
|
||||
'status' => 'sent',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
Sanctum::actingAs($sender);
|
||||
|
||||
$response = $this->deleteJson('/api/v1/messages/' . $message->id);
|
||||
|
||||
$response->assertOk();
|
||||
$this->assertDatabaseHas('messages', [
|
||||
'id' => $message->id,
|
||||
'status' => 'trashed',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_recipients_teacher_returns_list(): void
|
||||
{
|
||||
$teacher = $this->createUser('teacher', 'teacher@example.com');
|
||||
Sanctum::actingAs($teacher);
|
||||
|
||||
DB::table('teacher_class')->insert([
|
||||
'teacher_id' => $teacher->id,
|
||||
'class_section_id' => 1,
|
||||
'position' => 'main',
|
||||
'school_year' => '2025-2026',
|
||||
'semester' => 'Fall',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
$response = $this->getJson('/api/v1/messages/recipients/teacher');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('data.recipients.0.id', $teacher->id);
|
||||
}
|
||||
|
||||
public function test_validation_rejects_missing_subject(): void
|
||||
{
|
||||
$sender = $this->createUser('parent', 'sender5@example.com');
|
||||
$recipient = $this->createUser('teacher', 'recipient5@example.com');
|
||||
Sanctum::actingAs($sender);
|
||||
|
||||
$response = $this->postJson('/api/v1/messages', [
|
||||
'recipient_id' => $recipient->id,
|
||||
'message' => 'Body',
|
||||
]);
|
||||
|
||||
$response->assertStatus(422);
|
||||
$response->assertJsonStructure(['message', 'errors']);
|
||||
}
|
||||
|
||||
public function test_show_forbidden_for_other_users(): void
|
||||
{
|
||||
$sender = $this->createUser('parent', 'sender6@example.com');
|
||||
$recipient = $this->createUser('teacher', 'recipient6@example.com');
|
||||
$other = $this->createUser('student', 'other@example.com');
|
||||
|
||||
$message = Message::query()->create([
|
||||
'sender_id' => $sender->id,
|
||||
'recipient_id' => $recipient->id,
|
||||
'subject' => 'Subject',
|
||||
'message' => 'Body',
|
||||
'sent_datetime' => now(),
|
||||
'read_status' => 0,
|
||||
'message_number' => 'MSG-126',
|
||||
'priority' => 'normal',
|
||||
'status' => 'sent',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
Sanctum::actingAs($other);
|
||||
|
||||
$response = $this->getJson('/api/v1/messages/' . $message->id);
|
||||
|
||||
$response->assertForbidden();
|
||||
}
|
||||
|
||||
private function createUser(string $roleName, string $email): User
|
||||
{
|
||||
$roleId = DB::table('roles')->insertGetId([
|
||||
'name' => $roleName,
|
||||
'priority' => 1,
|
||||
'is_active' => 1,
|
||||
]);
|
||||
|
||||
$user = User::query()->create([
|
||||
'firstname' => 'Test',
|
||||
'lastname' => 'User',
|
||||
'email' => $email,
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
DB::table('user_roles')->insert([
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $roleId,
|
||||
]);
|
||||
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\V1\Settings;
|
||||
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class PolicyControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_school_policy_endpoint_returns_payload(): void
|
||||
{
|
||||
$response = $this->getJson('/api/v1/policies/school');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonStructure(['data' => ['policy' => ['type', 'title', 'format', 'content', 'updated_at']]]);
|
||||
}
|
||||
|
||||
public function test_picture_policy_endpoint_returns_payload(): void
|
||||
{
|
||||
$response = $this->getJson('/api/v1/policies/picture');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonStructure(['data' => ['policy' => ['type', 'title', 'format', 'content', 'updated_at']]]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\V1\Settings;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Tests\TestCase;
|
||||
|
||||
class PreferencesControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_show_returns_defaults(): void
|
||||
{
|
||||
$user = $this->createUser('teacher');
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->getJson('/api/v1/preferences');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('data.preferences.receive_email_notifications', true);
|
||||
$response->assertJsonStructure(['data' => ['options' => ['style_options', 'menu_options']]]);
|
||||
}
|
||||
|
||||
public function test_store_creates_preferences(): void
|
||||
{
|
||||
$user = $this->createUser('teacher');
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->postJson('/api/v1/preferences', [
|
||||
'receive_email_notifications' => true,
|
||||
'receive_sms_notifications' => false,
|
||||
'theme' => 'dark',
|
||||
'language' => 'en',
|
||||
'style_color' => 'blue',
|
||||
'menu_color' => 'white',
|
||||
]);
|
||||
|
||||
$response->assertOk();
|
||||
$this->assertDatabaseHas('user_preferences', [
|
||||
'user_id' => $user->id,
|
||||
'notification_email' => 1,
|
||||
'notification_sms' => 0,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_list_requires_admin(): void
|
||||
{
|
||||
$user = $this->createUser('teacher');
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->getJson('/api/v1/preferences/list');
|
||||
|
||||
$response->assertForbidden();
|
||||
}
|
||||
|
||||
public function test_list_returns_rows_for_admin(): void
|
||||
{
|
||||
$admin = $this->createUser('admin');
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
DB::table('user_preferences')->insert([
|
||||
'user_id' => $admin->id,
|
||||
'notification_email' => 1,
|
||||
'notification_sms' => 1,
|
||||
'theme' => 'light',
|
||||
'language' => 'en',
|
||||
]);
|
||||
|
||||
$response = $this->getJson('/api/v1/preferences/list');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('data.preferences.0.user_id', $admin->id);
|
||||
}
|
||||
|
||||
public function test_update_for_user_by_admin(): void
|
||||
{
|
||||
$admin = $this->createUser('admin');
|
||||
$user = $this->createUser('teacher', 2);
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
$response = $this->putJson('/api/v1/preferences/2', [
|
||||
'receive_sms_notifications' => false,
|
||||
]);
|
||||
|
||||
$response->assertOk();
|
||||
$this->assertDatabaseHas('user_preferences', [
|
||||
'user_id' => $user->id,
|
||||
'notification_sms' => 0,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_destroy_requires_admin(): void
|
||||
{
|
||||
$user = $this->createUser('teacher');
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->deleteJson('/api/v1/preferences/' . $user->id);
|
||||
|
||||
$response->assertForbidden();
|
||||
}
|
||||
|
||||
public function test_destroy_deletes_preferences(): void
|
||||
{
|
||||
$admin = $this->createUser('admin');
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
DB::table('user_preferences')->insert([
|
||||
'user_id' => $admin->id,
|
||||
'notification_email' => 1,
|
||||
'notification_sms' => 1,
|
||||
]);
|
||||
|
||||
$response = $this->deleteJson('/api/v1/preferences/' . $admin->id);
|
||||
|
||||
$response->assertOk();
|
||||
$this->assertDatabaseMissing('user_preferences', [
|
||||
'user_id' => $admin->id,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_store_validates_payload(): void
|
||||
{
|
||||
$user = $this->createUser('teacher');
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->postJson('/api/v1/preferences', [
|
||||
'theme' => 'invalid',
|
||||
]);
|
||||
|
||||
$response->assertStatus(422);
|
||||
$response->assertJsonStructure(['message', 'errors']);
|
||||
}
|
||||
|
||||
private function createUser(string $roleName, int $id = 1): User
|
||||
{
|
||||
$roleId = DB::table('roles')->insertGetId([
|
||||
'name' => $roleName,
|
||||
'priority' => 1,
|
||||
'is_active' => 1,
|
||||
]);
|
||||
|
||||
DB::table('users')->insert([
|
||||
'id' => $id,
|
||||
'firstname' => 'Test',
|
||||
'lastname' => 'User',
|
||||
'email' => $roleName . $id . '@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
DB::table('user_roles')->insert([
|
||||
'user_id' => $id,
|
||||
'role_id' => $roleId,
|
||||
]);
|
||||
|
||||
return User::query()->findOrFail($id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\V1\Settings;
|
||||
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Tests\TestCase;
|
||||
|
||||
class SettingsControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_index_requires_admin(): void
|
||||
{
|
||||
$user = $this->createUser('teacher');
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->getJson('/api/v1/settings');
|
||||
|
||||
$response->assertForbidden();
|
||||
}
|
||||
|
||||
public function test_index_returns_settings(): void
|
||||
{
|
||||
$admin = $this->createUser('admin');
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
$response = $this->getJson('/api/v1/settings');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonStructure(['data' => ['settings' => ['site_name', 'administrator_email', 'timezone']]]);
|
||||
}
|
||||
|
||||
public function test_update_validation_rejects_bad_email(): void
|
||||
{
|
||||
$admin = $this->createUser('admin');
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
$response = $this->patchJson('/api/v1/settings', [
|
||||
'administrator_email' => 'not-an-email',
|
||||
]);
|
||||
|
||||
$response->assertStatus(422);
|
||||
$response->assertJsonStructure(['message', 'errors']);
|
||||
}
|
||||
|
||||
public function test_update_persists_settings(): void
|
||||
{
|
||||
$admin = $this->createUser('admin');
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
$response = $this->patchJson('/api/v1/settings', [
|
||||
'site_name' => 'Alrahma',
|
||||
'timezone' => 'UTC',
|
||||
'administrator_email' => 'admin@example.com',
|
||||
]);
|
||||
|
||||
$response->assertOk();
|
||||
$this->assertDatabaseHas('settings', [
|
||||
'name' => 'Alrahma',
|
||||
'timezone' => 'UTC',
|
||||
]);
|
||||
$this->assertDatabaseHas('configuration', [
|
||||
'config_key' => 'administrator_email',
|
||||
'config_value' => 'admin@example.com',
|
||||
]);
|
||||
}
|
||||
|
||||
private function createUser(string $roleName): User
|
||||
{
|
||||
$roleId = DB::table('roles')->insertGetId([
|
||||
'name' => $roleName,
|
||||
'priority' => 1,
|
||||
'is_active' => 1,
|
||||
]);
|
||||
|
||||
$user = User::query()->create([
|
||||
'firstname' => 'Test',
|
||||
'lastname' => 'User',
|
||||
'email' => $roleName . '@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
DB::table('user_roles')->insert([
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $roleId,
|
||||
]);
|
||||
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\V1\Staff;
|
||||
|
||||
use App\Models\Staff;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Tests\TestCase;
|
||||
|
||||
class StaffControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_index_requires_admin(): void
|
||||
{
|
||||
$user = $this->createUser('teacher');
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->getJson('/api/v1/staff');
|
||||
|
||||
$response->assertForbidden();
|
||||
}
|
||||
|
||||
public function test_index_returns_staff(): void
|
||||
{
|
||||
$admin = $this->createUser('admin');
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
$staffUser = $this->createUser('teacher', 'staff@example.com');
|
||||
Staff::query()->create([
|
||||
'user_id' => $staffUser->id,
|
||||
'firstname' => 'Staff',
|
||||
'lastname' => 'User',
|
||||
'email' => 'staff@example.com',
|
||||
'phone' => '5555555555',
|
||||
'role_name' => 'teacher',
|
||||
'active_role' => 'teacher',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$response = $this->getJson('/api/v1/staff');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('data.staff.0.email', 'staff@example.com');
|
||||
}
|
||||
|
||||
public function test_store_creates_staff(): void
|
||||
{
|
||||
$admin = $this->createUser('admin');
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
$user = $this->createUser('teacher', 'newstaff@example.com');
|
||||
|
||||
$response = $this->postJson('/api/v1/staff', [
|
||||
'user_id' => $user->id,
|
||||
'firstname' => 'New',
|
||||
'lastname' => 'Staff',
|
||||
'email' => 'newstaff@example.com',
|
||||
'phone' => '5555555555',
|
||||
'role_name' => 'teacher',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$response->assertStatus(201);
|
||||
$this->assertDatabaseHas('staff', [
|
||||
'user_id' => $user->id,
|
||||
'email' => 'newstaff@example.com',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_store_validation(): void
|
||||
{
|
||||
$admin = $this->createUser('admin');
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
$response = $this->postJson('/api/v1/staff', [
|
||||
'firstname' => 'New',
|
||||
]);
|
||||
|
||||
$response->assertStatus(422);
|
||||
}
|
||||
|
||||
public function test_update_modifies_staff(): void
|
||||
{
|
||||
$admin = $this->createUser('admin');
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
$user = $this->createUser('teacher', 'updatestaff@example.com');
|
||||
$staff = Staff::query()->create([
|
||||
'user_id' => $user->id,
|
||||
'firstname' => 'Old',
|
||||
'lastname' => 'Name',
|
||||
'email' => 'updatestaff@example.com',
|
||||
'phone' => '5555555555',
|
||||
'role_name' => 'teacher',
|
||||
'active_role' => 'teacher',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$response = $this->patchJson('/api/v1/staff/' . $staff->id, [
|
||||
'firstname' => 'Updated',
|
||||
]);
|
||||
|
||||
$response->assertOk();
|
||||
$this->assertDatabaseHas('staff', [
|
||||
'id' => $staff->id,
|
||||
'firstname' => 'Updated',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_destroy_deletes_staff(): void
|
||||
{
|
||||
$admin = $this->createUser('admin');
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
$user = $this->createUser('teacher', 'deletestaff@example.com');
|
||||
$staff = Staff::query()->create([
|
||||
'user_id' => $user->id,
|
||||
'firstname' => 'Delete',
|
||||
'lastname' => 'Staff',
|
||||
'email' => 'deletestaff@example.com',
|
||||
'phone' => '5555555555',
|
||||
'role_name' => 'teacher',
|
||||
'active_role' => 'teacher',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$response = $this->deleteJson('/api/v1/staff/' . $staff->id);
|
||||
|
||||
$response->assertOk();
|
||||
$this->assertDatabaseMissing('staff', [
|
||||
'id' => $staff->id,
|
||||
]);
|
||||
}
|
||||
|
||||
private function createUser(string $roleName, ?string $email = null): User
|
||||
{
|
||||
$roleId = DB::table('roles')->insertGetId([
|
||||
'name' => $roleName,
|
||||
'priority' => 1,
|
||||
'is_active' => 1,
|
||||
]);
|
||||
|
||||
$user = User::query()->create([
|
||||
'firstname' => 'Test',
|
||||
'lastname' => 'User',
|
||||
'email' => $email ?? ($roleName . '@example.com'),
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
DB::table('user_roles')->insert([
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $roleId,
|
||||
]);
|
||||
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\V1\Support;
|
||||
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ContactControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_send_requires_valid_payload(): void
|
||||
{
|
||||
$response = $this->postJson('/api/v1/contact', [
|
||||
'email' => 'not-an-email',
|
||||
]);
|
||||
|
||||
$response->assertStatus(422);
|
||||
}
|
||||
|
||||
public function test_send_returns_success(): void
|
||||
{
|
||||
$response = $this->postJson('/api/v1/contact', [
|
||||
'name' => 'Test User',
|
||||
'email' => 'test@example.com',
|
||||
'subject' => 'Hello',
|
||||
'message' => 'This is a test message.',
|
||||
]);
|
||||
|
||||
$response->assertStatus(201);
|
||||
$response->assertJsonStructure(['data' => ['contact' => ['email_sent', 'recipient']]]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\V1\Support;
|
||||
|
||||
use App\Models\SupportRequest;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Tests\TestCase;
|
||||
|
||||
class SupportControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_index_requires_auth(): void
|
||||
{
|
||||
$response = $this->getJson('/api/v1/support');
|
||||
|
||||
$response->assertStatus(401);
|
||||
}
|
||||
|
||||
public function test_index_returns_requests(): void
|
||||
{
|
||||
$user = $this->createUser('parent');
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
SupportRequest::query()->create([
|
||||
'user_id' => $user->id,
|
||||
'subject' => 'Help',
|
||||
'message' => 'Need assistance',
|
||||
'status' => 'open',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$response = $this->getJson('/api/v1/support');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('data.requests.0.subject', 'Help');
|
||||
}
|
||||
|
||||
public function test_store_validation(): void
|
||||
{
|
||||
$user = $this->createUser('parent');
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->postJson('/api/v1/support', [
|
||||
'subject' => 'Hi',
|
||||
]);
|
||||
|
||||
$response->assertStatus(422);
|
||||
}
|
||||
|
||||
public function test_store_creates_request(): void
|
||||
{
|
||||
DB::table('configuration')->insert([
|
||||
['config_key' => 'school_year', 'config_value' => '2025-2026'],
|
||||
['config_key' => 'semester', 'config_value' => 'Fall'],
|
||||
]);
|
||||
|
||||
$user = $this->createUser('parent');
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->postJson('/api/v1/support', [
|
||||
'subject' => 'Help',
|
||||
'message' => 'Need assistance please',
|
||||
]);
|
||||
|
||||
$response->assertStatus(201);
|
||||
$this->assertDatabaseHas('support_requests', [
|
||||
'user_id' => $user->id,
|
||||
'subject' => 'Help',
|
||||
]);
|
||||
}
|
||||
|
||||
private function createUser(string $roleName): User
|
||||
{
|
||||
$roleId = DB::table('roles')->insertGetId([
|
||||
'name' => $roleName,
|
||||
'priority' => 1,
|
||||
'is_active' => 1,
|
||||
]);
|
||||
|
||||
$user = User::query()->create([
|
||||
'firstname' => 'Test',
|
||||
'lastname' => 'User',
|
||||
'email' => $roleName . '@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
DB::table('user_roles')->insert([
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $roleId,
|
||||
]);
|
||||
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\V1\System;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Tests\TestCase;
|
||||
|
||||
class DashboardControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_route_requires_authentication(): void
|
||||
{
|
||||
$response = $this->getJson('/api/v1/dashboard/route');
|
||||
|
||||
$response->assertStatus(401);
|
||||
}
|
||||
|
||||
public function test_route_returns_dashboard_for_role(): void
|
||||
{
|
||||
$roleId = DB::table('roles')->insertGetId([
|
||||
'name' => 'administrator',
|
||||
'dashboard_route' => '/administrator/dashboard',
|
||||
'priority' => 1,
|
||||
'is_active' => 1,
|
||||
]);
|
||||
|
||||
$user = User::query()->create([
|
||||
'firstname' => 'Admin',
|
||||
'lastname' => 'User',
|
||||
'email' => 'admin@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
DB::table('user_roles')->insert([
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $roleId,
|
||||
]);
|
||||
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->getJson('/api/v1/dashboard/route');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('data.dashboard.route', '/administrator/dashboard');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\V1\System;
|
||||
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class DatabaseHealthControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_db_check_returns_ok(): void
|
||||
{
|
||||
$response = $this->getJson('/api/v1/system/db-check');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('data.ok', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\V1\System;
|
||||
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class HealthControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_health_returns_payload(): void
|
||||
{
|
||||
$response = $this->getJson('/api/v1/health');
|
||||
|
||||
$this->assertContains($response->status(), [200, 503]);
|
||||
$response->assertJsonStructure([
|
||||
'status',
|
||||
'message',
|
||||
'data' => [
|
||||
'health' => [
|
||||
'ok',
|
||||
'paths',
|
||||
'database',
|
||||
'write_path',
|
||||
'timestamp',
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\V1\System;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class NavBuilderControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
private function makeAdminUser(): User
|
||||
{
|
||||
$roleId = DB::table('roles')->insertGetId([
|
||||
'name' => 'admin',
|
||||
'priority' => 1,
|
||||
]);
|
||||
|
||||
$user = User::query()->create([
|
||||
'firstname' => 'Admin',
|
||||
'lastname' => 'User',
|
||||
'email' => 'admin@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'CT',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => 'hashed',
|
||||
'semester' => 'Fall',
|
||||
]);
|
||||
|
||||
DB::table('user_roles')->insert([
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $roleId,
|
||||
]);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function test_menu_returns_items_for_roles(): void
|
||||
{
|
||||
$roleId = DB::table('roles')->insertGetId([
|
||||
'name' => 'parent',
|
||||
'priority' => 1,
|
||||
]);
|
||||
|
||||
$user = User::query()->create([
|
||||
'firstname' => 'Parent',
|
||||
'lastname' => 'User',
|
||||
'email' => 'parent@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'CT',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => 'hashed',
|
||||
'semester' => 'Fall',
|
||||
]);
|
||||
|
||||
DB::table('user_roles')->insert([
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $roleId,
|
||||
]);
|
||||
|
||||
$navId = DB::table('nav_items')->insertGetId([
|
||||
'label' => 'Home',
|
||||
'url' => 'home',
|
||||
'sort_order' => 1,
|
||||
'is_enabled' => 1,
|
||||
]);
|
||||
|
||||
DB::table('role_nav_items')->insert([
|
||||
'role_id' => $roleId,
|
||||
'nav_item_id' => $navId,
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($user, 'sanctum')->getJson('/api/v1/nav-builder/menu');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('data.items.0.label', 'Home');
|
||||
}
|
||||
|
||||
public function test_data_requires_admin(): void
|
||||
{
|
||||
$user = $this->makeAdminUser();
|
||||
|
||||
$response = $this->actingAs($user, 'sanctum')->getJson('/api/v1/nav-builder/data');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonStructure(['data' => ['data' => ['items', 'roles', 'parentOptions']]]);
|
||||
}
|
||||
|
||||
public function test_store_creates_nav_item(): void
|
||||
{
|
||||
$user = $this->makeAdminUser();
|
||||
|
||||
$response = $this->actingAs($user, 'sanctum')->postJson('/api/v1/nav-builder', [
|
||||
'label' => 'Dashboard',
|
||||
'url' => 'dashboard',
|
||||
'sort_order' => 1,
|
||||
'is_enabled' => true,
|
||||
'roles' => [],
|
||||
]);
|
||||
|
||||
$response->assertCreated();
|
||||
$this->assertDatabaseHas('nav_items', ['label' => 'Dashboard']);
|
||||
}
|
||||
|
||||
public function test_delete_removes_nav_item(): void
|
||||
{
|
||||
$user = $this->makeAdminUser();
|
||||
|
||||
$navId = DB::table('nav_items')->insertGetId([
|
||||
'label' => 'Delete',
|
||||
'url' => 'delete',
|
||||
'sort_order' => 1,
|
||||
'is_enabled' => 1,
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($user, 'sanctum')->deleteJson("/api/v1/nav-builder/{$navId}");
|
||||
|
||||
$response->assertOk();
|
||||
$this->assertDatabaseMissing('nav_items', ['id' => $navId]);
|
||||
}
|
||||
|
||||
public function test_reorder_updates_items(): void
|
||||
{
|
||||
$user = $this->makeAdminUser();
|
||||
|
||||
$navId = DB::table('nav_items')->insertGetId([
|
||||
'label' => 'Sort',
|
||||
'url' => 'sort',
|
||||
'sort_order' => 1,
|
||||
'is_enabled' => 1,
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($user, 'sanctum')->postJson('/api/v1/nav-builder/reorder', [
|
||||
'orders' => [$navId => 9],
|
||||
]);
|
||||
|
||||
$response->assertOk();
|
||||
$this->assertDatabaseHas('nav_items', ['id' => $navId, 'sort_order' => 9]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\V1\Ui;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Tests\TestCase;
|
||||
|
||||
class UiControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_style_requires_auth(): void
|
||||
{
|
||||
$response = $this->postJson('/api/v1/ui/style', [
|
||||
'accent' => 'blue',
|
||||
]);
|
||||
|
||||
$response->assertStatus(401);
|
||||
}
|
||||
|
||||
public function test_style_updates_preferences(): void
|
||||
{
|
||||
$user = $this->createUser('parent');
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->postJson('/api/v1/ui/style', [
|
||||
'accent' => 'blue',
|
||||
'menu' => 'custom',
|
||||
'menu_bg' => '#112233',
|
||||
'menu_text' => '#ffffff',
|
||||
'menu_mode' => 'dark',
|
||||
]);
|
||||
|
||||
$response->assertOk();
|
||||
$this->assertDatabaseHas('user_preferences', [
|
||||
'user_id' => $user->id,
|
||||
'style_color' => 'blue',
|
||||
'menu_color' => 'custom',
|
||||
]);
|
||||
}
|
||||
|
||||
private function createUser(string $roleName): User
|
||||
{
|
||||
$roleId = DB::table('roles')->insertGetId([
|
||||
'name' => $roleName,
|
||||
'priority' => 1,
|
||||
'is_active' => 1,
|
||||
]);
|
||||
|
||||
$user = User::query()->create([
|
||||
'firstname' => 'Test',
|
||||
'lastname' => 'User',
|
||||
'email' => $roleName . '@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
DB::table('user_roles')->insert([
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $roleId,
|
||||
]);
|
||||
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\V1\Utilities;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Tests\TestCase;
|
||||
|
||||
class PhoneFormatterControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_format_returns_formatted_phone(): void
|
||||
{
|
||||
$user = $this->createUser();
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->postJson('/api/v1/utilities/phone/format', [
|
||||
'number' => '(555) 123-4567',
|
||||
]);
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('data.phone.formatted', '555-123-4567');
|
||||
$response->assertJsonPath('data.phone.is_valid', true);
|
||||
}
|
||||
|
||||
public function test_format_rejects_invalid_number(): void
|
||||
{
|
||||
$user = $this->createUser();
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->postJson('/api/v1/utilities/phone/format', [
|
||||
'number' => '123',
|
||||
]);
|
||||
|
||||
$response->assertStatus(422);
|
||||
}
|
||||
|
||||
public function test_format_validates_payload(): void
|
||||
{
|
||||
$user = $this->createUser();
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->postJson('/api/v1/utilities/phone/format', []);
|
||||
|
||||
$response->assertStatus(422);
|
||||
$response->assertJsonStructure(['message', 'errors']);
|
||||
}
|
||||
|
||||
private function createUser(): User
|
||||
{
|
||||
$roleId = DB::table('roles')->insertGetId([
|
||||
'name' => 'admin',
|
||||
'priority' => 1,
|
||||
'is_active' => 1,
|
||||
]);
|
||||
|
||||
$user = User::query()->create([
|
||||
'firstname' => 'Test',
|
||||
'lastname' => 'User',
|
||||
'email' => 'admin@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
DB::table('user_roles')->insert([
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $roleId,
|
||||
]);
|
||||
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Middleware;
|
||||
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Tests\TestCase;
|
||||
|
||||
class RequirePermissionMiddlewareTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_denies_when_missing_permission(): void
|
||||
{
|
||||
Route::middleware('perm:edit_students')->get('/test-perm', fn () => 'ok');
|
||||
|
||||
$user = User::query()->create([
|
||||
'firstname' => 'No',
|
||||
'lastname' => 'Perm',
|
||||
'email' => 'noperm@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'CT',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => 'hashed',
|
||||
'semester' => 'Fall',
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($user)->get('/test-perm', ['Accept' => 'application/json']);
|
||||
|
||||
$response->assertStatus(403);
|
||||
}
|
||||
|
||||
public function test_allows_when_permission_assigned(): void
|
||||
{
|
||||
$permissionId = DB::table('permissions')->insertGetId([
|
||||
'name' => 'edit_students',
|
||||
'description' => 'Edit students',
|
||||
]);
|
||||
|
||||
$roleId = DB::table('roles')->insertGetId([
|
||||
'name' => 'admin',
|
||||
'priority' => 1,
|
||||
]);
|
||||
|
||||
$user = User::query()->create([
|
||||
'firstname' => 'Has',
|
||||
'lastname' => 'Perm',
|
||||
'email' => 'hasperm@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'CT',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => 'hashed',
|
||||
'semester' => 'Fall',
|
||||
]);
|
||||
|
||||
DB::table('user_roles')->insert([
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $roleId,
|
||||
]);
|
||||
|
||||
DB::table('role_permissions')->insert([
|
||||
'role_id' => $roleId,
|
||||
'permission_id' => $permissionId,
|
||||
'can_read' => 1,
|
||||
]);
|
||||
|
||||
Route::middleware('perm:edit_students')->get('/test-perm-ok', fn () => 'ok');
|
||||
|
||||
$response = $this->actingAs($user)->get('/test-perm-ok');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertSee('ok');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Resources\Frontend;
|
||||
|
||||
use App\Http\Resources\Frontend\FrontendPageResource;
|
||||
use Tests\TestCase;
|
||||
|
||||
class FrontendPageResourceTest extends TestCase
|
||||
{
|
||||
public function test_resource_returns_page(): void
|
||||
{
|
||||
$resource = new FrontendPageResource(['page' => 'index']);
|
||||
$payload = $resource->toArray(request());
|
||||
|
||||
$this->assertSame('index', $payload['page']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Resources\Frontend;
|
||||
|
||||
use App\Http\Resources\Frontend\PageContentResource;
|
||||
use Tests\TestCase;
|
||||
|
||||
class PageContentResourceTest extends TestCase
|
||||
{
|
||||
public function test_resource_returns_content(): void
|
||||
{
|
||||
$resource = new PageContentResource([
|
||||
'type' => 'privacy_policy',
|
||||
'content' => '<h1>Privacy</h1>',
|
||||
]);
|
||||
|
||||
$payload = $resource->toArray(request());
|
||||
|
||||
$this->assertSame('privacy_policy', $payload['type']);
|
||||
$this->assertSame('<h1>Privacy</h1>', $payload['content']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Resources\Messaging;
|
||||
|
||||
use App\Http\Resources\Messaging\MessageResource;
|
||||
use App\Models\Message;
|
||||
use Tests\TestCase;
|
||||
|
||||
class MessageResourceTest extends TestCase
|
||||
{
|
||||
public function test_resource_returns_expected_shape(): void
|
||||
{
|
||||
$message = new Message([
|
||||
'id' => 1,
|
||||
'sender_id' => 2,
|
||||
'recipient_id' => 3,
|
||||
'subject' => 'Hello',
|
||||
'message' => 'Body',
|
||||
'sent_datetime' => now(),
|
||||
'read_status' => 0,
|
||||
'message_number' => 'MSG-1',
|
||||
'priority' => 'normal',
|
||||
'status' => 'sent',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$payload = (new MessageResource($message))->toArray(request());
|
||||
|
||||
$this->assertArrayHasKey('id', $payload);
|
||||
$this->assertArrayHasKey('subject', $payload);
|
||||
$this->assertArrayHasKey('message_number', $payload);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Resources\Messaging;
|
||||
|
||||
use App\Http\Resources\Messaging\RecipientResource;
|
||||
use Tests\TestCase;
|
||||
|
||||
class RecipientResourceTest extends TestCase
|
||||
{
|
||||
public function test_resource_returns_expected_shape(): void
|
||||
{
|
||||
$resource = new RecipientResource(['id' => 5, 'name' => 'Test User']);
|
||||
$payload = $resource->toArray(request());
|
||||
|
||||
$this->assertSame(5, $payload['id']);
|
||||
$this->assertSame('Test User', $payload['name']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Resources\Settings;
|
||||
|
||||
use App\Http\Resources\Settings\SettingsResource;
|
||||
use Tests\TestCase;
|
||||
|
||||
class SettingsResourceTest extends TestCase
|
||||
{
|
||||
public function test_resource_returns_expected_shape(): void
|
||||
{
|
||||
$resource = new SettingsResource([
|
||||
'site_name' => 'App',
|
||||
'administrator_email' => 'admin@example.com',
|
||||
'timezone' => 'UTC',
|
||||
]);
|
||||
|
||||
$payload = $resource->toArray(request());
|
||||
|
||||
$this->assertSame('App', $payload['site_name']);
|
||||
$this->assertSame('admin@example.com', $payload['administrator_email']);
|
||||
$this->assertSame('UTC', $payload['timezone']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Resources\Staff;
|
||||
|
||||
use App\Http\Resources\Staff\StaffResource;
|
||||
use App\Models\Staff;
|
||||
use Tests\TestCase;
|
||||
|
||||
class StaffResourceTest extends TestCase
|
||||
{
|
||||
public function test_resource_returns_expected_shape(): void
|
||||
{
|
||||
$staff = new Staff([
|
||||
'id' => 1,
|
||||
'user_id' => 2,
|
||||
'firstname' => 'Test',
|
||||
'lastname' => 'User',
|
||||
'email' => 'test@example.com',
|
||||
'role_name' => 'teacher',
|
||||
'active_role' => 'teacher',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$payload = (new StaffResource($staff))->toArray(request());
|
||||
|
||||
$this->assertSame(1, $payload['id']);
|
||||
$this->assertSame('teacher', $payload['role_name']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Resources\Support;
|
||||
|
||||
use App\Http\Resources\Support\ContactMessageResource;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ContactMessageResourceTest extends TestCase
|
||||
{
|
||||
public function test_resource_returns_expected_shape(): void
|
||||
{
|
||||
$resource = new ContactMessageResource([
|
||||
'email_sent' => true,
|
||||
'recipient' => 'support@example.com',
|
||||
]);
|
||||
|
||||
$payload = $resource->toArray(request());
|
||||
|
||||
$this->assertTrue($payload['email_sent']);
|
||||
$this->assertSame('support@example.com', $payload['recipient']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Resources\Support;
|
||||
|
||||
use App\Http\Resources\Support\SupportRequestResource;
|
||||
use App\Models\SupportRequest;
|
||||
use Tests\TestCase;
|
||||
|
||||
class SupportRequestResourceTest extends TestCase
|
||||
{
|
||||
public function test_resource_returns_expected_shape(): void
|
||||
{
|
||||
$model = new SupportRequest([
|
||||
'id' => 1,
|
||||
'user_id' => 2,
|
||||
'subject' => 'Help',
|
||||
'message' => 'Need help',
|
||||
'status' => 'open',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$payload = (new SupportRequestResource($model))->toArray(request());
|
||||
|
||||
$this->assertSame(1, $payload['id']);
|
||||
$this->assertSame('Help', $payload['subject']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Resources\Ui;
|
||||
|
||||
use App\Http\Resources\Ui\UiStyleResource;
|
||||
use App\Models\Preferences;
|
||||
use Tests\TestCase;
|
||||
|
||||
class UiStyleResourceTest extends TestCase
|
||||
{
|
||||
public function test_resource_returns_expected_shape(): void
|
||||
{
|
||||
$prefs = new Preferences([
|
||||
'style_color' => 'blue',
|
||||
'menu_color' => 'custom',
|
||||
'menu_custom_bg' => '#112233',
|
||||
'menu_custom_text' => '#FFFFFF',
|
||||
'menu_custom_mode' => 'dark',
|
||||
]);
|
||||
|
||||
$payload = (new UiStyleResource($prefs))->toArray(request());
|
||||
|
||||
$this->assertSame('blue', $payload['style_color']);
|
||||
$this->assertSame('custom', $payload['menu_color']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Attendance;
|
||||
|
||||
use App\Models\LateSlipLog;
|
||||
use App\Services\Attendance\LateSlipLogCommandService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class LateSlipLogCommandServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_delete_removes_log(): void
|
||||
{
|
||||
$log = LateSlipLog::query()->create([
|
||||
'school_year' => '2025-2026',
|
||||
'semester' => 'Fall',
|
||||
'student_name' => 'Student X',
|
||||
'slip_date' => '2025-09-01',
|
||||
'time_in' => '08:05:00',
|
||||
'grade' => '4',
|
||||
'reason' => 'Traffic',
|
||||
'admin_name' => 'Admin User',
|
||||
]);
|
||||
|
||||
$service = app(LateSlipLogCommandService::class);
|
||||
$deleted = $service->delete($log);
|
||||
|
||||
$this->assertTrue($deleted);
|
||||
$this->assertDatabaseMissing('late_slip_logs', ['id' => $log->id]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Attendance;
|
||||
|
||||
use App\Services\Attendance\LateSlipLogQueryService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class LateSlipLogQueryServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_paginate_filters_by_date(): void
|
||||
{
|
||||
DB::table('late_slip_logs')->insert([
|
||||
[
|
||||
'school_year' => '2025-2026',
|
||||
'semester' => 'Fall',
|
||||
'student_name' => 'Student A',
|
||||
'slip_date' => '2025-09-01',
|
||||
],
|
||||
[
|
||||
'school_year' => '2025-2026',
|
||||
'semester' => 'Fall',
|
||||
'student_name' => 'Student B',
|
||||
'slip_date' => '2025-10-01',
|
||||
],
|
||||
]);
|
||||
|
||||
$service = app(LateSlipLogQueryService::class);
|
||||
$pager = $service->paginate(['date_from' => '2025-10-01'], 1, 10);
|
||||
|
||||
$this->assertSame(1, $pager->total());
|
||||
$this->assertSame('Student B', $pager->items()[0]->student_name);
|
||||
}
|
||||
}
|
||||
@@ -10,24 +10,24 @@ class RegistrationCaptchaServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_generate_sets_session_value(): void
|
||||
public function test_generate_sets_cache_value(): void
|
||||
{
|
||||
$service = new RegistrationCaptchaService();
|
||||
$value = $service->generate(6);
|
||||
|
||||
$this->assertNotEmpty($value);
|
||||
$this->assertSame($value, session()->get('captcha_answer'));
|
||||
$this->assertTrue($service->verify($value));
|
||||
}
|
||||
|
||||
public function test_verify_and_clear(): void
|
||||
{
|
||||
$service = new RegistrationCaptchaService();
|
||||
session()->put('captcha_answer', 'ABC123');
|
||||
$value = $service->generate(6);
|
||||
|
||||
$this->assertTrue($service->verify('ABC123'));
|
||||
$this->assertTrue($service->verify($value));
|
||||
$this->assertFalse($service->verify('WRONG'));
|
||||
|
||||
$service->clear();
|
||||
$this->assertNull(session()->get('captcha_answer'));
|
||||
$this->assertFalse($service->verify($value));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,8 @@ class RegistrationServiceTest extends TestCase
|
||||
'is_active' => 1,
|
||||
]);
|
||||
|
||||
session()->put('captcha_answer', 'ABCD');
|
||||
$captchaService = new RegistrationCaptchaService();
|
||||
$captcha = $captchaService->generate(4);
|
||||
|
||||
$emailService = Mockery::mock(EmailService::class);
|
||||
$emailService->shouldReceive('send')->once()->andReturn(true);
|
||||
@@ -44,7 +45,7 @@ class RegistrationServiceTest extends TestCase
|
||||
$emailService,
|
||||
new SchoolIdService(),
|
||||
new RegistrationFormatterService(new PhoneFormatterService()),
|
||||
new RegistrationCaptchaService()
|
||||
$captchaService
|
||||
);
|
||||
|
||||
$result = $service->register([
|
||||
@@ -60,7 +61,7 @@ class RegistrationServiceTest extends TestCase
|
||||
'state' => 'CT',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'captcha' => 'ABCD',
|
||||
'captcha' => $captcha,
|
||||
'is_parent' => 1,
|
||||
'no_second_parent_info' => 1,
|
||||
]);
|
||||
@@ -114,7 +115,8 @@ class RegistrationServiceTest extends TestCase
|
||||
'token' => 'token',
|
||||
]);
|
||||
|
||||
session()->put('captcha_answer', 'ABCD');
|
||||
$captchaService = new RegistrationCaptchaService();
|
||||
$captcha = $captchaService->generate(4);
|
||||
|
||||
$emailService = Mockery::mock(EmailService::class);
|
||||
$emailService->shouldNotReceive('send');
|
||||
@@ -123,7 +125,7 @@ class RegistrationServiceTest extends TestCase
|
||||
$emailService,
|
||||
new SchoolIdService(),
|
||||
new RegistrationFormatterService(new PhoneFormatterService()),
|
||||
new RegistrationCaptchaService()
|
||||
$captchaService
|
||||
);
|
||||
|
||||
$result = $service->register([
|
||||
@@ -139,7 +141,7 @@ class RegistrationServiceTest extends TestCase
|
||||
'state' => 'CT',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'captcha' => 'ABCD',
|
||||
'captcha' => $captcha,
|
||||
'is_parent' => 1,
|
||||
'no_second_parent_info' => 1,
|
||||
]);
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Auth;
|
||||
|
||||
use App\Services\Auth\SessionActivityService;
|
||||
use Illuminate\Session\ArraySessionHandler;
|
||||
use Illuminate\Session\Store;
|
||||
use Tests\TestCase;
|
||||
|
||||
class SessionActivityServiceTest extends TestCase
|
||||
{
|
||||
public function test_set_and_get_last_activity(): void
|
||||
{
|
||||
$store = $this->makeSessionStore();
|
||||
$service = new SessionActivityService($store);
|
||||
|
||||
$service->setLastActivity(12345);
|
||||
|
||||
$this->assertTrue($service->hasLastActivity());
|
||||
$this->assertSame(12345, $service->getLastActivity());
|
||||
}
|
||||
|
||||
public function test_clear_last_activity(): void
|
||||
{
|
||||
$store = $this->makeSessionStore();
|
||||
$service = new SessionActivityService($store);
|
||||
|
||||
$service->setLastActivity(12345);
|
||||
$service->clearLastActivity();
|
||||
|
||||
$this->assertFalse($service->hasLastActivity());
|
||||
}
|
||||
|
||||
private function makeSessionStore(): Store
|
||||
{
|
||||
$handler = new ArraySessionHandler(10);
|
||||
$store = new Store('test', $handler);
|
||||
$store->start();
|
||||
|
||||
return $store;
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Auth;
|
||||
|
||||
use App\Services\Auth\SessionTimeoutConfigService;
|
||||
use Tests\TestCase;
|
||||
|
||||
class SessionTimeoutConfigServiceTest extends TestCase
|
||||
{
|
||||
public function test_config_returns_expected_keys(): void
|
||||
{
|
||||
$service = new SessionTimeoutConfigService();
|
||||
$config = $service->config();
|
||||
|
||||
$this->assertArrayHasKey('timeout', $config);
|
||||
$this->assertArrayHasKey('warning_time', $config);
|
||||
$this->assertArrayHasKey('check_interval', $config);
|
||||
$this->assertArrayHasKey('logout_url', $config);
|
||||
$this->assertArrayHasKey('keep_alive_url', $config);
|
||||
$this->assertArrayHasKey('check_url', $config);
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Auth;
|
||||
|
||||
use App\Config\SessionTimeout;
|
||||
use App\Services\Auth\SessionActivityService;
|
||||
use App\Services\Auth\SessionTimeoutService;
|
||||
use Mockery;
|
||||
use Tests\TestCase;
|
||||
|
||||
class SessionTimeoutServiceTest extends TestCase
|
||||
{
|
||||
public function test_check_timeout_returns_expired_when_missing_activity(): void
|
||||
{
|
||||
$activity = Mockery::mock(SessionActivityService::class);
|
||||
$activity->shouldReceive('hasLastActivity')->andReturn(false);
|
||||
$activity->shouldReceive('clearLastActivity')->once();
|
||||
$activity->shouldReceive('invalidate')->once();
|
||||
|
||||
$service = new SessionTimeoutService($activity);
|
||||
$result = $service->checkTimeout();
|
||||
|
||||
$this->assertSame('expired', $result['status']);
|
||||
}
|
||||
|
||||
public function test_check_timeout_returns_warning(): void
|
||||
{
|
||||
$activity = Mockery::mock(SessionActivityService::class);
|
||||
$activity->shouldReceive('hasLastActivity')->andReturn(true);
|
||||
$activity->shouldReceive('getLastActivity')->andReturn(time() - (SessionTimeout::WARNING_THRESHOLD + 10));
|
||||
|
||||
$service = new SessionTimeoutService($activity);
|
||||
$result = $service->checkTimeout();
|
||||
|
||||
$this->assertSame('warning', $result['status']);
|
||||
}
|
||||
|
||||
public function test_ping_returns_expired_when_timed_out(): void
|
||||
{
|
||||
$activity = Mockery::mock(SessionActivityService::class);
|
||||
$activity->shouldReceive('hasLastActivity')->andReturn(true);
|
||||
$activity->shouldReceive('getLastActivity')->andReturn(time() - (SessionTimeout::TIMEOUT_DURATION + 10));
|
||||
$activity->shouldReceive('clearLastActivity')->once();
|
||||
$activity->shouldReceive('invalidate')->once();
|
||||
|
||||
$service = new SessionTimeoutService($activity);
|
||||
$result = $service->pingActivity();
|
||||
|
||||
$this->assertSame('expired', $result['status']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Auth;
|
||||
|
||||
use App\Services\Auth\UserRoleService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class UserRoleServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_has_permission_for_crud_checks_roles(): void
|
||||
{
|
||||
$permissionId = DB::table('permissions')->insertGetId([
|
||||
'name' => 'manage_students',
|
||||
'description' => 'Manage students',
|
||||
]);
|
||||
|
||||
$roleId = DB::table('roles')->insertGetId([
|
||||
'name' => 'admin',
|
||||
'priority' => 1,
|
||||
]);
|
||||
|
||||
DB::table('user_roles')->insert([
|
||||
'user_id' => 5,
|
||||
'role_id' => $roleId,
|
||||
]);
|
||||
|
||||
DB::table('role_permissions')->insert([
|
||||
'role_id' => $roleId,
|
||||
'permission_id' => $permissionId,
|
||||
'can_read' => 1,
|
||||
'can_manage' => 0,
|
||||
]);
|
||||
|
||||
$service = new UserRoleService();
|
||||
$roleIds = $service->getRoleIds(5);
|
||||
|
||||
$this->assertTrue($service->hasPermissionForCrud($roleIds, 'manage_students', 'read'));
|
||||
$this->assertFalse($service->hasPermissionForCrud($roleIds, 'manage_students', 'delete'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\ClassPreparation;
|
||||
|
||||
use App\Services\ClassPreparation\ClassPreparationAdjustmentWriterService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ClassPreparationAdjustmentWriterServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_save_adjustments_persists_allowed_items(): void
|
||||
{
|
||||
$service = app(ClassPreparationAdjustmentWriterService::class);
|
||||
|
||||
$count = $service->saveAdjustments('101', '2025-2026', [
|
||||
'Small Table' => 2,
|
||||
'Unknown Item' => 5,
|
||||
], ['Small Table']);
|
||||
|
||||
$this->assertSame(1, $count);
|
||||
$this->assertDatabaseHas('class_prep_adjustments', [
|
||||
'class_section_id' => '101',
|
||||
'school_year' => '2025-2026',
|
||||
'item_name' => 'Small Table',
|
||||
'adjustment' => 2,
|
||||
]);
|
||||
$this->assertDatabaseMissing('class_prep_adjustments', [
|
||||
'item_name' => 'Unknown Item',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\ClassPreparation;
|
||||
|
||||
use App\Services\ClassPreparation\ClassPreparationAdjustmentService;
|
||||
use App\Services\ClassPreparation\ClassPreparationCalculatorService;
|
||||
use App\Services\ClassPreparation\ClassPreparationContextService;
|
||||
use App\Services\ClassPreparation\ClassPreparationLogService;
|
||||
use App\Services\ClassPreparation\ClassPreparationPrintService;
|
||||
use App\Services\ClassPreparation\ClassPreparationRosterService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Mockery;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ClassPreparationPrintServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
Mockery::close();
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public function test_print_prep_creates_log(): void
|
||||
{
|
||||
$this->seedPrepData();
|
||||
|
||||
$service = app(ClassPreparationPrintService::class);
|
||||
$payload = $service->printPrep('101', '2025-2026', 'Fall');
|
||||
|
||||
$this->assertTrue($payload['ok']);
|
||||
$this->assertDatabaseHas('class_preparation_log', [
|
||||
'class_section_id' => 101,
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_print_prep_handles_log_failure(): void
|
||||
{
|
||||
$context = Mockery::mock(ClassPreparationContextService::class);
|
||||
$roster = Mockery::mock(ClassPreparationRosterService::class);
|
||||
$calculator = Mockery::mock(ClassPreparationCalculatorService::class);
|
||||
$adjustments = Mockery::mock(ClassPreparationAdjustmentService::class);
|
||||
$logs = Mockery::mock(ClassPreparationLogService::class);
|
||||
|
||||
$context->shouldReceive('getSemester')->andReturn('Fall');
|
||||
$context->shouldReceive('hasRosterForSemester')->andReturn(true);
|
||||
$roster->shouldReceive('getStudentCountForSection')->andReturn(10);
|
||||
$calculator->shouldReceive('getClassLevelBySection')->andReturn(2);
|
||||
$calculator->shouldReceive('calculatePrepItems')->andReturn(['Small Table' => 2]);
|
||||
$adjustments->shouldReceive('applyAdjustments')->andReturn([['Small Table' => 2], []]);
|
||||
$logs->shouldReceive('createLog')->andReturn(false);
|
||||
|
||||
$service = new ClassPreparationPrintService($context, $roster, $calculator, $adjustments, $logs);
|
||||
$payload = $service->printPrep('101', '2025-2026', 'Fall');
|
||||
|
||||
$this->assertFalse($payload['ok']);
|
||||
$this->assertNull($payload['printed_at']);
|
||||
}
|
||||
|
||||
private function seedPrepData(): void
|
||||
{
|
||||
DB::table('configuration')->insert([
|
||||
['config_key' => 'school_year', 'config_value' => '2025-2026'],
|
||||
['config_key' => 'semester', 'config_value' => 'Fall'],
|
||||
]);
|
||||
|
||||
DB::table('classSection')->insert([
|
||||
'id' => 1,
|
||||
'class_id' => 1,
|
||||
'class_section_id' => 101,
|
||||
'class_section_name' => '1-A',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
DB::table('students')->insert([
|
||||
'school_id' => 'S-1',
|
||||
'firstname' => 'Student',
|
||||
'lastname' => 'One',
|
||||
'age' => 8,
|
||||
'gender' => 'Male',
|
||||
'photo_consent' => 1,
|
||||
'parent_id' => 1,
|
||||
'year_of_registration' => '2025',
|
||||
'school_year' => '2025-2026',
|
||||
'semester' => 'Fall',
|
||||
'is_active' => 1,
|
||||
]);
|
||||
|
||||
DB::table('student_class')->insert([
|
||||
'student_id' => 1,
|
||||
'class_section_id' => 101,
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
DB::table('inventory_categories')->insert([
|
||||
'type' => 'classroom',
|
||||
'name' => 'Small Table',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\ClassSections;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Services\ClassSections\ClassAttendanceService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ClassAttendanceServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_get_attendance_payload_includes_students(): void
|
||||
{
|
||||
DB::table('configuration')->insert([
|
||||
['config_key' => 'school_year', 'config_value' => '2025-2026'],
|
||||
['config_key' => 'semester', 'config_value' => 'Fall'],
|
||||
]);
|
||||
|
||||
DB::table('classSection')->insert([
|
||||
'class_id' => 1,
|
||||
'class_section_id' => 101,
|
||||
'class_section_name' => '1-A',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
DB::table('students')->insert([
|
||||
'school_id' => 'S-1',
|
||||
'firstname' => 'Student',
|
||||
'lastname' => 'One',
|
||||
'age' => 8,
|
||||
'gender' => 'Male',
|
||||
'photo_consent' => 1,
|
||||
'parent_id' => 1,
|
||||
'year_of_registration' => '2025',
|
||||
'school_year' => '2025-2026',
|
||||
'semester' => 'Fall',
|
||||
'is_active' => 1,
|
||||
]);
|
||||
|
||||
DB::table('student_class')->insert([
|
||||
'student_id' => 1,
|
||||
'class_section_id' => 101,
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$teacher = User::query()->create([
|
||||
'firstname' => 'Teach',
|
||||
'lastname' => 'Er',
|
||||
'email' => 'teacher@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$service = app(ClassAttendanceService::class);
|
||||
$payload = $service->getAttendancePayload(101, $teacher->id);
|
||||
|
||||
$this->assertSame('1-A', $payload['class_name']);
|
||||
$this->assertCount(1, $payload['students']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\ClassSections;
|
||||
|
||||
use App\Models\ClassSection;
|
||||
use App\Services\ClassSections\ClassSectionCommandService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ClassSectionCommandServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_create_update_delete(): void
|
||||
{
|
||||
$service = app(ClassSectionCommandService::class);
|
||||
|
||||
$section = $service->create([
|
||||
'class_id' => 1,
|
||||
'class_section_id' => 101,
|
||||
'class_section_name' => '1-A',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$this->assertInstanceOf(ClassSection::class, $section);
|
||||
$this->assertDatabaseHas('classSection', ['id' => $section->id]);
|
||||
|
||||
$updated = $service->update($section, ['class_section_name' => '1-B']);
|
||||
$this->assertSame('1-B', $updated->class_section_name);
|
||||
|
||||
$deleted = $service->delete($section);
|
||||
$this->assertTrue($deleted);
|
||||
$this->assertDatabaseMissing('classSection', ['id' => $section->id]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\ClassSections;
|
||||
|
||||
use App\Services\ClassSections\ClassSectionQueryService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ClassSectionQueryServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_list_filters_by_search(): void
|
||||
{
|
||||
DB::table('classes')->insert([
|
||||
'class_name' => 'Class 1',
|
||||
'schedule' => 'Monday',
|
||||
'capacity' => 30,
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
DB::table('classSection')->insert([
|
||||
[
|
||||
'class_id' => 1,
|
||||
'class_section_id' => 101,
|
||||
'class_section_name' => '1-A',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
],
|
||||
[
|
||||
'class_id' => 1,
|
||||
'class_section_id' => 102,
|
||||
'class_section_name' => '2-B',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
],
|
||||
]);
|
||||
|
||||
$service = app(ClassSectionQueryService::class);
|
||||
$pager = $service->list(['search' => '1-A'], 1, 10);
|
||||
|
||||
$this->assertSame(1, $pager->total());
|
||||
$this->assertSame('1-A', $pager->items()[0]->class_section_name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\ClassSections;
|
||||
|
||||
use App\Services\ClassSections\ClassSectionSeedService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ClassSectionSeedServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_seed_defaults_creates_rows(): void
|
||||
{
|
||||
DB::table('configuration')->insert([
|
||||
['config_key' => 'school_year', 'config_value' => '2025-2026'],
|
||||
['config_key' => 'semester', 'config_value' => 'Fall'],
|
||||
]);
|
||||
|
||||
$service = app(ClassSectionSeedService::class);
|
||||
$count = $service->seedDefaults();
|
||||
|
||||
$this->assertGreaterThan(0, $count);
|
||||
$this->assertDatabaseHas('classes', [
|
||||
'class_name' => 'Class 1',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Dashboard;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Services\Dashboard\DashboardRouteService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class DashboardRouteServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_resolve_returns_fallback_when_no_roles(): void
|
||||
{
|
||||
$user = User::query()->create([
|
||||
'firstname' => 'No',
|
||||
'lastname' => 'Role',
|
||||
'email' => 'norole@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$service = app(DashboardRouteService::class);
|
||||
$payload = $service->resolveForUser($user);
|
||||
|
||||
$this->assertSame('/landing_page/guest_dashboard', $payload['route']);
|
||||
}
|
||||
|
||||
public function test_resolve_returns_dashboard_route_for_role(): void
|
||||
{
|
||||
$roleId = DB::table('roles')->insertGetId([
|
||||
'name' => 'administrator',
|
||||
'dashboard_route' => '/administrator/dashboard',
|
||||
'priority' => 1,
|
||||
'is_active' => 1,
|
||||
]);
|
||||
|
||||
$user = User::query()->create([
|
||||
'firstname' => 'Admin',
|
||||
'lastname' => 'User',
|
||||
'email' => 'admin@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
DB::table('user_roles')->insert([
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $roleId,
|
||||
]);
|
||||
|
||||
$service = app(DashboardRouteService::class);
|
||||
$payload = $service->resolveForUser($user);
|
||||
|
||||
$this->assertSame('/administrator/dashboard', $payload['route']);
|
||||
$this->assertSame('administrator', strtolower((string) $payload['role']));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Frontend;
|
||||
|
||||
use App\Services\Email\EmailDispatchService;
|
||||
use App\Services\Frontend\ContactSubmissionService;
|
||||
use App\Services\System\GlobalConfigService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ContactSubmissionServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_submit_creates_contact_record(): void
|
||||
{
|
||||
DB::table('configuration')->insert([
|
||||
['config_key' => 'school_year', 'config_value' => '2025-2026'],
|
||||
['config_key' => 'semester', 'config_value' => 'Fall'],
|
||||
]);
|
||||
|
||||
$emailService = $this->createMock(EmailDispatchService::class);
|
||||
$emailService->method('send')->willReturn(false);
|
||||
|
||||
$service = new ContactSubmissionService($emailService, new GlobalConfigService());
|
||||
|
||||
$result = $service->submit([
|
||||
'email' => 'contact@example.com',
|
||||
'message' => 'Hello from unit test',
|
||||
]);
|
||||
|
||||
$this->assertNotNull($result['record']);
|
||||
$this->assertDatabaseHas('contactus', [
|
||||
'subject' => 'Contact Us Form Submission',
|
||||
'semester' => 'Fall',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Frontend;
|
||||
|
||||
use App\Services\Frontend\FrontendPageService;
|
||||
use Tests\TestCase;
|
||||
|
||||
class FrontendPageServiceTest extends TestCase
|
||||
{
|
||||
public function test_page_returns_payload(): void
|
||||
{
|
||||
$service = new FrontendPageService();
|
||||
$payload = $service->page('index');
|
||||
|
||||
$this->assertSame('index', $payload['page']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Frontend;
|
||||
|
||||
use App\Services\Frontend\LandingPageContextService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class LandingPageContextServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_context_returns_config_values(): void
|
||||
{
|
||||
DB::table('configuration')->insert([
|
||||
['config_key' => 'school_year', 'config_value' => '2025-2026'],
|
||||
['config_key' => 'semester', 'config_value' => 'Fall'],
|
||||
['config_key' => 'enrollment_deadline', 'config_value' => '2025-09-01'],
|
||||
['config_key' => 'refund_deadline', 'config_value' => '2025-10-01'],
|
||||
]);
|
||||
|
||||
$service = app(LandingPageContextService::class);
|
||||
$context = $service->context();
|
||||
|
||||
$this->assertSame('2025-2026', $context['school_year']);
|
||||
$this->assertSame('Fall', $context['semester']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Frontend;
|
||||
|
||||
use App\Services\Frontend\LandingPageParentDashboardService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class LandingPageParentDashboardServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_summary_returns_parent_payload(): void
|
||||
{
|
||||
DB::table('configuration')->insert([
|
||||
['config_key' => 'school_year', 'config_value' => '2025-2026'],
|
||||
['config_key' => 'semester', 'config_value' => 'Fall'],
|
||||
]);
|
||||
|
||||
DB::table('students')->insert([
|
||||
'id' => 1,
|
||||
'school_id' => 'S-1',
|
||||
'firstname' => 'Student',
|
||||
'lastname' => 'One',
|
||||
'age' => 8,
|
||||
'gender' => 'Male',
|
||||
'photo_consent' => 1,
|
||||
'parent_id' => 1,
|
||||
'year_of_registration' => '2025',
|
||||
'school_year' => '2025-2026',
|
||||
'semester' => 'Fall',
|
||||
'is_active' => 1,
|
||||
]);
|
||||
|
||||
DB::table('classSection')->insert([
|
||||
'class_id' => 1,
|
||||
'class_section_id' => 101,
|
||||
'class_section_name' => '1-A',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
DB::table('student_class')->insert([
|
||||
'student_id' => 1,
|
||||
'class_section_id' => 101,
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$service = app(LandingPageParentDashboardService::class);
|
||||
$payload = $service->summary(1, 'primary');
|
||||
|
||||
$this->assertTrue($payload['ok']);
|
||||
$this->assertCount(1, $payload['students']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Frontend;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Services\Frontend\LandingPageRoleService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class LandingPageRoleServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_resolve_role_returns_guest_when_missing(): void
|
||||
{
|
||||
$service = app(LandingPageRoleService::class);
|
||||
$this->assertSame('guest', $service->resolveRole(null));
|
||||
}
|
||||
|
||||
public function test_resolve_role_returns_first_role(): void
|
||||
{
|
||||
$roleId = DB::table('roles')->insertGetId([
|
||||
'name' => 'teacher',
|
||||
'priority' => 1,
|
||||
'is_active' => 1,
|
||||
]);
|
||||
|
||||
$user = User::query()->create([
|
||||
'firstname' => 'Teach',
|
||||
'lastname' => 'Er',
|
||||
'email' => 'teacher@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
DB::table('user_roles')->insert([
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $roleId,
|
||||
]);
|
||||
|
||||
$service = app(LandingPageRoleService::class);
|
||||
$this->assertSame('teacher', $service->resolveRole($user));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Frontend;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Services\Frontend\LandingPageService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class LandingPageServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_dashboard_for_user_returns_guest(): void
|
||||
{
|
||||
$service = app(LandingPageService::class);
|
||||
$payload = $service->dashboardForUser(null);
|
||||
|
||||
$this->assertSame('guest', $payload['role']);
|
||||
}
|
||||
|
||||
public function test_dashboard_for_user_returns_admin(): void
|
||||
{
|
||||
$roleId = DB::table('roles')->insertGetId([
|
||||
'name' => 'admin',
|
||||
'priority' => 1,
|
||||
'is_active' => 1,
|
||||
]);
|
||||
|
||||
$user = User::query()->create([
|
||||
'firstname' => 'Admin',
|
||||
'lastname' => 'User',
|
||||
'email' => 'admin@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
DB::table('user_roles')->insert([
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $roleId,
|
||||
]);
|
||||
|
||||
$service = app(LandingPageService::class);
|
||||
$payload = $service->dashboardForUser($user);
|
||||
|
||||
$this->assertSame('admin', $payload['role']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Frontend;
|
||||
|
||||
use App\Services\Frontend\LandingPageTeacherSummaryService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class LandingPageTeacherSummaryServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_summary_returns_dashboard_payload(): void
|
||||
{
|
||||
DB::table('configuration')->insert([
|
||||
['config_key' => 'school_year', 'config_value' => '2025-2026'],
|
||||
['config_key' => 'semester', 'config_value' => 'Fall'],
|
||||
]);
|
||||
|
||||
DB::table('teacher_class')->insert([
|
||||
'teacher_id' => 1,
|
||||
'class_section_id' => 101,
|
||||
'position' => 'main',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
DB::table('classSection')->insert([
|
||||
'class_id' => 1,
|
||||
'class_section_id' => 101,
|
||||
'class_section_name' => '1-A',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$service = app(LandingPageTeacherSummaryService::class);
|
||||
$payload = $service->summary(1);
|
||||
|
||||
$this->assertSame(101, $payload['class_section_id']);
|
||||
$this->assertArrayHasKey('scoreSummary', $payload);
|
||||
$this->assertArrayHasKey('attendanceSummary', $payload);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Frontend;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Services\Frontend\ProfileIconService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ProfileIconServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_build_for_user_returns_initials(): void
|
||||
{
|
||||
$user = User::query()->create([
|
||||
'firstname' => 'Jane',
|
||||
'lastname' => 'Smith',
|
||||
'email' => 'jane@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$service = app(ProfileIconService::class);
|
||||
$payload = $service->buildForUser($user->id);
|
||||
|
||||
$this->assertSame('JS', $payload['userInitials']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Frontend;
|
||||
|
||||
use App\Services\Frontend\StaticPageService;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Tests\TestCase;
|
||||
|
||||
class StaticPageServiceTest extends TestCase
|
||||
{
|
||||
public function test_load_returns_content(): void
|
||||
{
|
||||
$dir = public_path('html');
|
||||
File::ensureDirectoryExists($dir);
|
||||
File::put($dir . '/terms_of_service.html', '<h1>Terms</h1>');
|
||||
|
||||
$service = new StaticPageService();
|
||||
$result = $service->load('terms_of_service.html', 'terms_of_service');
|
||||
|
||||
$this->assertTrue($result['ok']);
|
||||
$this->assertSame('terms_of_service', $result['type']);
|
||||
$this->assertStringContainsString('Terms', $result['content']);
|
||||
}
|
||||
|
||||
public function test_load_missing_returns_error(): void
|
||||
{
|
||||
$service = new StaticPageService();
|
||||
$result = $service->load('missing.html', 'missing');
|
||||
|
||||
$this->assertFalse($result['ok']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Messaging;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Services\Messaging\MessageCommandService;
|
||||
use App\Services\System\GlobalConfigService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class MessageCommandServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_create_sends_message(): void
|
||||
{
|
||||
DB::table('configuration')->insert([
|
||||
['config_key' => 'school_year', 'config_value' => '2025-2026'],
|
||||
['config_key' => 'semester', 'config_value' => 'Fall'],
|
||||
]);
|
||||
|
||||
$sender = $this->createUser('sender@example.com');
|
||||
$recipient = $this->createUser('recipient@example.com');
|
||||
|
||||
$service = new MessageCommandService(new GlobalConfigService());
|
||||
$message = $service->create($sender->id, [
|
||||
'recipient_id' => $recipient->id,
|
||||
'subject' => 'Subject',
|
||||
'message' => 'Body',
|
||||
]);
|
||||
|
||||
$this->assertNotNull($message->id);
|
||||
$this->assertDatabaseHas('messages', [
|
||||
'id' => $message->id,
|
||||
'subject' => 'Subject',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_create_rejects_invalid_role(): void
|
||||
{
|
||||
$sender = $this->createUser('sender2@example.com');
|
||||
|
||||
$service = new MessageCommandService(new GlobalConfigService());
|
||||
|
||||
$this->expectException(\RuntimeException::class);
|
||||
$service->create($sender->id, [
|
||||
'recipient_role' => 'invalid',
|
||||
'subject' => 'Subject',
|
||||
'message' => 'Body',
|
||||
]);
|
||||
}
|
||||
|
||||
private function createUser(string $email): User
|
||||
{
|
||||
return User::query()->create([
|
||||
'firstname' => 'Test',
|
||||
'lastname' => 'User',
|
||||
'email' => $email,
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Messaging;
|
||||
|
||||
use App\Models\Message;
|
||||
use App\Models\User;
|
||||
use App\Services\Messaging\MessageQueryService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class MessageQueryServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_inbox_filters_messages(): void
|
||||
{
|
||||
$sender = $this->createUser('sender@example.com');
|
||||
$recipient = $this->createUser('recipient@example.com');
|
||||
|
||||
Message::query()->create([
|
||||
'sender_id' => $sender->id,
|
||||
'recipient_id' => $recipient->id,
|
||||
'subject' => 'Hello',
|
||||
'message' => 'Body',
|
||||
'sent_datetime' => now(),
|
||||
'read_status' => 0,
|
||||
'message_number' => 'MSG-10',
|
||||
'priority' => 'normal',
|
||||
'status' => 'sent',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$service = new MessageQueryService();
|
||||
$paginator = $service->inbox($recipient->id, [], 1, 20);
|
||||
|
||||
$this->assertSame(1, $paginator->total());
|
||||
}
|
||||
|
||||
private function createUser(string $email): User
|
||||
{
|
||||
return User::query()->create([
|
||||
'firstname' => 'Test',
|
||||
'lastname' => 'User',
|
||||
'email' => $email,
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Messaging;
|
||||
|
||||
use App\Models\ParentModel;
|
||||
use App\Models\Student;
|
||||
use App\Models\User;
|
||||
use App\Services\Messaging\MessageRecipientService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class MessageRecipientServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_teachers_returns_list(): void
|
||||
{
|
||||
$teacher = $this->createUser('teacher@example.com');
|
||||
|
||||
DB::table('teacher_class')->insert([
|
||||
'teacher_id' => $teacher->id,
|
||||
'class_section_id' => 1,
|
||||
'position' => 'main',
|
||||
'school_year' => '2025-2026',
|
||||
'semester' => 'Fall',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
$service = new MessageRecipientService();
|
||||
$rows = $service->teachers();
|
||||
|
||||
$this->assertSame($teacher->id, $rows[0]['id']);
|
||||
}
|
||||
|
||||
public function test_parents_returns_list(): void
|
||||
{
|
||||
$teacher = $this->createUser('teacher2@example.com');
|
||||
$parent = $this->createUser('parent@example.com');
|
||||
$secondParent = $this->createUser('parent2@example.com');
|
||||
|
||||
DB::table('teacher_class')->insert([
|
||||
'teacher_id' => $teacher->id,
|
||||
'class_section_id' => 2,
|
||||
'position' => 'main',
|
||||
'school_year' => '2025-2026',
|
||||
'semester' => 'Fall',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
$studentId = Student::query()->insertGetId([
|
||||
'school_id' => 'S-1',
|
||||
'firstname' => 'Student',
|
||||
'lastname' => 'One',
|
||||
'age' => 10,
|
||||
'gender' => 'Male',
|
||||
'photo_consent' => 1,
|
||||
'parent_id' => $parent->id,
|
||||
'year_of_registration' => '2025',
|
||||
'is_active' => 1,
|
||||
'is_new' => 1,
|
||||
]);
|
||||
|
||||
DB::table('student_class')->insert([
|
||||
'student_id' => $studentId,
|
||||
'class_section_id' => 2,
|
||||
'school_year' => '2025-2026',
|
||||
'semester' => 'Fall',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
ParentModel::query()->create([
|
||||
'secondparent_firstname' => 'Second',
|
||||
'secondparent_lastname' => 'Parent',
|
||||
'secondparent_email' => 'parent2@example.com',
|
||||
'secondparent_phone' => '5555555555',
|
||||
'firstparent_id' => $parent->id,
|
||||
'secondparent_id' => $secondParent->id,
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$service = new MessageRecipientService();
|
||||
$rows = $service->parents();
|
||||
|
||||
$ids = array_column($rows, 'id');
|
||||
$this->assertContains($parent->id, $ids);
|
||||
$this->assertContains($secondParent->id, $ids);
|
||||
}
|
||||
|
||||
private function createUser(string $email): User
|
||||
{
|
||||
return User::query()->create([
|
||||
'firstname' => 'Test',
|
||||
'lastname' => 'User',
|
||||
'email' => $email,
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Navigation;
|
||||
|
||||
use App\Services\Navigation\NavBuilderService;
|
||||
use App\Services\Navigation\NavbarService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class NavBuilderServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_save_creates_nav_item_and_roles(): void
|
||||
{
|
||||
$roleId = DB::table('roles')->insertGetId([
|
||||
'name' => 'admin',
|
||||
'priority' => 1,
|
||||
]);
|
||||
|
||||
$service = new NavBuilderService(new NavbarService());
|
||||
$result = $service->save([
|
||||
'label' => 'Dashboard',
|
||||
'url' => 'dashboard',
|
||||
'sort_order' => 1,
|
||||
'is_enabled' => 1,
|
||||
'roles' => [$roleId],
|
||||
]);
|
||||
|
||||
$this->assertTrue($result['ok']);
|
||||
$this->assertDatabaseHas('nav_items', ['label' => 'Dashboard']);
|
||||
$this->assertDatabaseHas('role_nav_items', [
|
||||
'role_id' => $roleId,
|
||||
'nav_item_id' => $result['id'],
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_reorder_updates_sort_order(): void
|
||||
{
|
||||
$id = DB::table('nav_items')->insertGetId([
|
||||
'label' => 'Item',
|
||||
'url' => 'item',
|
||||
'sort_order' => 1,
|
||||
'is_enabled' => 1,
|
||||
]);
|
||||
|
||||
$service = new NavBuilderService(new NavbarService());
|
||||
$service->reorder([$id => 5]);
|
||||
|
||||
$this->assertDatabaseHas('nav_items', [
|
||||
'id' => $id,
|
||||
'sort_order' => 5,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Navigation;
|
||||
|
||||
use App\Services\Navigation\NavbarService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class NavbarServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_get_menu_for_roles_builds_tree(): void
|
||||
{
|
||||
$roleId = DB::table('roles')->insertGetId([
|
||||
'name' => 'admin',
|
||||
'priority' => 1,
|
||||
]);
|
||||
|
||||
$parentId = DB::table('nav_items')->insertGetId([
|
||||
'label' => 'Parent',
|
||||
'url' => 'parent',
|
||||
'sort_order' => 1,
|
||||
'is_enabled' => 1,
|
||||
]);
|
||||
|
||||
$childId = DB::table('nav_items')->insertGetId([
|
||||
'label' => 'Child',
|
||||
'url' => 'child',
|
||||
'menu_parent_id' => $parentId,
|
||||
'sort_order' => 2,
|
||||
'is_enabled' => 1,
|
||||
]);
|
||||
|
||||
DB::table('role_nav_items')->insert([
|
||||
['role_id' => $roleId, 'nav_item_id' => $parentId],
|
||||
['role_id' => $roleId, 'nav_item_id' => $childId],
|
||||
]);
|
||||
|
||||
$service = new NavbarService();
|
||||
$menu = $service->getMenuForRoles(['admin']);
|
||||
|
||||
$this->assertCount(1, $menu);
|
||||
$this->assertSame('Parent', $menu[0]['label']);
|
||||
$this->assertCount(1, $menu[0]['children']);
|
||||
$this->assertSame('Child', $menu[0]['children'][0]['label']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Phone;
|
||||
|
||||
use App\Services\Phone\PhoneFormatterService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class PhoneFormatterServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_format_returns_null_for_invalid(): void
|
||||
{
|
||||
$service = app(PhoneFormatterService::class);
|
||||
|
||||
$this->assertNull($service->format('123'));
|
||||
}
|
||||
|
||||
public function test_format_formats_digits(): void
|
||||
{
|
||||
$service = app(PhoneFormatterService::class);
|
||||
|
||||
$this->assertSame('555-123-4567', $service->format('(555) 123-4567'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Policy;
|
||||
|
||||
use App\Services\Policy\PolicyContentService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class PolicyContentServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_get_policy_returns_content(): void
|
||||
{
|
||||
$service = new PolicyContentService();
|
||||
$result = $service->getPolicy('school');
|
||||
|
||||
$this->assertSame('school', $result['type']);
|
||||
$this->assertSame('School Policy', $result['title']);
|
||||
$this->assertSame('html', $result['format']);
|
||||
$this->assertNotEmpty($result['content']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Preferences;
|
||||
|
||||
use App\Services\Preferences\PreferencesCommandService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class PreferencesCommandServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_upsert_creates_record(): void
|
||||
{
|
||||
$service = app(PreferencesCommandService::class);
|
||||
$pref = $service->upsert(1, [
|
||||
'receive_email_notifications' => true,
|
||||
'receive_sms_notifications' => false,
|
||||
'theme' => 'light',
|
||||
'language' => 'en',
|
||||
]);
|
||||
|
||||
$this->assertSame(1, $pref->user_id);
|
||||
$this->assertDatabaseHas('user_preferences', [
|
||||
'user_id' => 1,
|
||||
'notification_email' => 1,
|
||||
'notification_sms' => 0,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Preferences;
|
||||
|
||||
use App\Services\Preferences\PreferencesOptionsService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class PreferencesOptionsServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_defaults_include_expected_keys(): void
|
||||
{
|
||||
$service = app(PreferencesOptionsService::class);
|
||||
$defaults = $service->defaultPreferences();
|
||||
|
||||
$this->assertArrayHasKey('receive_email_notifications', $defaults);
|
||||
$this->assertArrayHasKey('receive_sms_notifications', $defaults);
|
||||
$this->assertSame('light', $defaults['theme']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Preferences;
|
||||
|
||||
use App\Services\Preferences\PreferencesQueryService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class PreferencesQueryServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_get_for_user_returns_defaults_when_missing(): void
|
||||
{
|
||||
$service = app(PreferencesQueryService::class);
|
||||
$payload = $service->getForUser(1);
|
||||
|
||||
$this->assertTrue($payload['preferences']['receive_email_notifications']);
|
||||
$this->assertSame('en', $payload['preferences']['language']);
|
||||
}
|
||||
|
||||
public function test_paginate_filters_by_user_id(): void
|
||||
{
|
||||
DB::table('users')->insert([
|
||||
'id' => 1,
|
||||
'firstname' => 'Test',
|
||||
'lastname' => 'User',
|
||||
'email' => 'test@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
DB::table('user_preferences')->insert([
|
||||
'user_id' => 1,
|
||||
'notification_email' => 1,
|
||||
'notification_sms' => 1,
|
||||
]);
|
||||
|
||||
$service = app(PreferencesQueryService::class);
|
||||
$pager = $service->paginate(['user_id' => 1], 1, 10);
|
||||
|
||||
$this->assertSame(1, $pager->total());
|
||||
$this->assertSame(1, $pager->items()[0]->user_id);
|
||||
}
|
||||
}
|
||||
@@ -13,11 +13,9 @@ class SemesterSelectionServiceTest extends TestCase
|
||||
|
||||
public function test_selected_teacher_semester_prefers_session_value(): void
|
||||
{
|
||||
session()->put('teacher_scores_selected_semester', 'spring');
|
||||
|
||||
$service = new SemesterSelectionService();
|
||||
|
||||
$this->assertSame('Spring', $service->selectedTeacherSemester());
|
||||
$this->assertSame('Fall', $service->selectedTeacherSemester());
|
||||
}
|
||||
|
||||
public function test_selected_teacher_semester_falls_back_to_config(): void
|
||||
@@ -26,9 +24,6 @@ class SemesterSelectionServiceTest extends TestCase
|
||||
['config_key' => 'semester', 'config_value' => 'Fall'],
|
||||
]);
|
||||
|
||||
session()->forget('teacher_scores_selected_semester');
|
||||
session()->forget('semester');
|
||||
|
||||
$service = new SemesterSelectionService();
|
||||
|
||||
$this->assertSame('Fall', $service->selectedTeacherSemester());
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Security;
|
||||
|
||||
use App\Services\Security\IpBanCommandService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class IpBanCommandServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_ban_now_updates_blocked_until(): void
|
||||
{
|
||||
DB::table('ip_attempts')->insert([
|
||||
'ip_address' => '10.0.0.9',
|
||||
'attempts' => 1,
|
||||
]);
|
||||
|
||||
$service = app(IpBanCommandService::class);
|
||||
$ban = $service->banNow(null, '10.0.0.9', 2);
|
||||
|
||||
$this->assertNotNull($ban);
|
||||
$this->assertDatabaseHas('ip_attempts', [
|
||||
'ip_address' => '10.0.0.9',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_unban_all_resets_active(): void
|
||||
{
|
||||
DB::table('ip_attempts')->insert([
|
||||
'ip_address' => '10.0.0.10',
|
||||
'attempts' => 5,
|
||||
'blocked_until' => now('UTC')->addHours(3),
|
||||
]);
|
||||
|
||||
$service = app(IpBanCommandService::class);
|
||||
$count = $service->unbanAll();
|
||||
|
||||
$this->assertSame(1, $count);
|
||||
$this->assertDatabaseHas('ip_attempts', [
|
||||
'ip_address' => '10.0.0.10',
|
||||
'blocked_until' => null,
|
||||
'attempts' => 0,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Security;
|
||||
|
||||
use App\Services\Security\IpBanQueryService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class IpBanQueryServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_paginate_filters_active(): void
|
||||
{
|
||||
DB::table('ip_attempts')->insert([
|
||||
[
|
||||
'ip_address' => '10.0.0.1',
|
||||
'attempts' => 2,
|
||||
'blocked_until' => now('UTC')->addHours(2),
|
||||
],
|
||||
[
|
||||
'ip_address' => '10.0.0.2',
|
||||
'attempts' => 2,
|
||||
'blocked_until' => now('UTC')->subHours(1),
|
||||
],
|
||||
]);
|
||||
|
||||
$service = app(IpBanQueryService::class);
|
||||
$pager = $service->paginate(['status' => 'active'], 1, 10);
|
||||
|
||||
$this->assertSame(1, $pager->total());
|
||||
$this->assertSame('10.0.0.1', $pager->items()[0]->ip_address);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Settings;
|
||||
|
||||
use App\Models\Setting;
|
||||
use App\Services\Settings\SettingsService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class SettingsServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_update_persists_settings(): void
|
||||
{
|
||||
$service = new SettingsService();
|
||||
|
||||
$result = $service->update([
|
||||
'site_name' => 'Alrahma',
|
||||
'timezone' => 'UTC',
|
||||
'administrator_email' => 'admin@example.com',
|
||||
], 1);
|
||||
|
||||
$this->assertSame('Alrahma', $result['site_name']);
|
||||
$this->assertDatabaseHas('settings', [
|
||||
'name' => 'Alrahma',
|
||||
'timezone' => 'UTC',
|
||||
]);
|
||||
$this->assertDatabaseHas('configuration', [
|
||||
'config_key' => 'administrator_email',
|
||||
'config_value' => 'admin@example.com',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Staff;
|
||||
|
||||
use App\Models\Staff;
|
||||
use App\Models\User;
|
||||
use App\Services\Staff\StaffCommandService;
|
||||
use App\Services\System\GlobalConfigService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class StaffCommandServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_create_requires_user(): void
|
||||
{
|
||||
$service = new StaffCommandService(new GlobalConfigService());
|
||||
|
||||
$this->expectException(\RuntimeException::class);
|
||||
$service->create([
|
||||
'firstname' => 'Test',
|
||||
'lastname' => 'User',
|
||||
'email' => 'missing@example.com',
|
||||
'role_name' => 'teacher',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_create_with_user_id(): void
|
||||
{
|
||||
$user = User::query()->create([
|
||||
'firstname' => 'Test',
|
||||
'lastname' => 'User',
|
||||
'email' => 'staffcmd@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$service = new StaffCommandService(new GlobalConfigService());
|
||||
$staff = $service->create([
|
||||
'user_id' => $user->id,
|
||||
'firstname' => 'Staff',
|
||||
'lastname' => 'User',
|
||||
'email' => 'staffcmd@example.com',
|
||||
'role_name' => 'teacher',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$this->assertInstanceOf(Staff::class, $staff);
|
||||
$this->assertSame($user->id, $staff->user_id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Staff;
|
||||
|
||||
use App\Models\Staff;
|
||||
use App\Models\User;
|
||||
use App\Services\Staff\StaffQueryService;
|
||||
use App\Services\System\GlobalConfigService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class StaffQueryServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_paginate_returns_staff(): void
|
||||
{
|
||||
$user = User::query()->create([
|
||||
'firstname' => 'Test',
|
||||
'lastname' => 'User',
|
||||
'email' => 'staffquery@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
Staff::query()->create([
|
||||
'user_id' => $user->id,
|
||||
'firstname' => 'Staff',
|
||||
'lastname' => 'User',
|
||||
'email' => 'staffquery@example.com',
|
||||
'role_name' => 'teacher',
|
||||
'active_role' => 'teacher',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$service = new StaffQueryService(new GlobalConfigService());
|
||||
$result = $service->paginate([], 1, 10);
|
||||
|
||||
$this->assertSame(1, $result['paginator']->total());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Support;
|
||||
|
||||
use App\Services\Email\EmailDispatchService;
|
||||
use App\Services\Support\ContactMessageService;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ContactMessageServiceTest extends TestCase
|
||||
{
|
||||
public function test_send_returns_payload(): void
|
||||
{
|
||||
$mailer = $this->createMock(EmailDispatchService::class);
|
||||
$mailer->method('send')->willReturn(false);
|
||||
|
||||
$service = new ContactMessageService($mailer);
|
||||
$result = $service->send([
|
||||
'name' => 'Test User',
|
||||
'email' => 'test@example.com',
|
||||
'subject' => 'Hello',
|
||||
'message' => 'Message',
|
||||
]);
|
||||
|
||||
$this->assertArrayHasKey('email_sent', $result);
|
||||
$this->assertArrayHasKey('recipient', $result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Support;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Services\Email\EmailDispatchService;
|
||||
use App\Services\Support\SupportRequestService;
|
||||
use App\Services\System\GlobalConfigService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class SupportRequestServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_create_persists_request(): void
|
||||
{
|
||||
DB::table('configuration')->insert([
|
||||
['config_key' => 'school_year', 'config_value' => '2025-2026'],
|
||||
['config_key' => 'semester', 'config_value' => 'Fall'],
|
||||
]);
|
||||
|
||||
$user = User::query()->create([
|
||||
'firstname' => 'Test',
|
||||
'lastname' => 'User',
|
||||
'email' => 'supporter@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$mailer = $this->createMock(EmailDispatchService::class);
|
||||
$mailer->method('send')->willReturn(false);
|
||||
|
||||
$service = new SupportRequestService(new GlobalConfigService(), $mailer);
|
||||
$result = $service->create($user->id, [
|
||||
'subject' => 'Help',
|
||||
'message' => 'Need assistance',
|
||||
]);
|
||||
|
||||
$this->assertNotNull($result['record']);
|
||||
$this->assertDatabaseHas('support_requests', [
|
||||
'user_id' => $user->id,
|
||||
'subject' => 'Help',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\System;
|
||||
|
||||
use App\Services\System\CleanupSchedulerService;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Tests\TestCase;
|
||||
|
||||
class CleanupSchedulerServiceTest extends TestCase
|
||||
{
|
||||
public function test_should_run_when_no_cache(): void
|
||||
{
|
||||
Cache::forget('last_cleanup_run');
|
||||
|
||||
$service = new CleanupSchedulerService();
|
||||
$this->assertTrue($service->shouldRun('last_cleanup_run', 2));
|
||||
}
|
||||
|
||||
public function test_mark_run_sets_cache(): void
|
||||
{
|
||||
$service = new CleanupSchedulerService();
|
||||
$service->markRun('last_cleanup_run');
|
||||
|
||||
$this->assertNotNull(Cache::get('last_cleanup_run'));
|
||||
}
|
||||
|
||||
public function test_run_unverified_cleanup_calls_artisan(): void
|
||||
{
|
||||
Artisan::shouldReceive('call')->once()->with('users:delete-unverified');
|
||||
|
||||
$service = new CleanupSchedulerService();
|
||||
$service->runUnverifiedCleanup();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\System;
|
||||
|
||||
use App\Services\System\HealthCheckService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class HealthCheckServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_check_returns_payload(): void
|
||||
{
|
||||
$service = app(HealthCheckService::class);
|
||||
$payload = $service->check();
|
||||
|
||||
$this->assertArrayHasKey('ok', $payload);
|
||||
$this->assertArrayHasKey('paths', $payload);
|
||||
$this->assertArrayHasKey('database', $payload);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Ui;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Services\Ui\UiStyleService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class UiStyleServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_update_creates_preferences(): void
|
||||
{
|
||||
$user = User::query()->create([
|
||||
'firstname' => 'Test',
|
||||
'lastname' => 'User',
|
||||
'email' => 'ui@example.com',
|
||||
'cellphone' => '5555555555',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'status' => 'Active',
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$service = new UiStyleService();
|
||||
$prefs = $service->update($user->id, [
|
||||
'accent' => 'blue',
|
||||
'menu' => 'custom',
|
||||
'menu_bg' => '#112233',
|
||||
'menu_text' => '#ffffff',
|
||||
'menu_mode' => 'dark',
|
||||
]);
|
||||
|
||||
$this->assertSame('blue', $prefs->style_color);
|
||||
$this->assertSame('custom', $prefs->menu_color);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user