Initial Ladill Frontdesk release with deploy pipeline.
Visitor management app with SSO, kiosk, badges, reports, and Gitea CI deploy to frontdesk.ladill.com. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Http\Middleware\EnsurePlatformSession;
|
||||
use App\Models\Branch;
|
||||
use App\Models\Device;
|
||||
use App\Models\Host;
|
||||
use App\Models\Member;
|
||||
use App\Models\Organization;
|
||||
use App\Models\User;
|
||||
use App\Models\Visit;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Tests\TestCase;
|
||||
|
||||
class FrontdeskPhase7Test extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected User $user;
|
||||
|
||||
protected Organization $organization;
|
||||
|
||||
protected string $deviceToken;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->withoutMiddleware(EnsurePlatformSession::class);
|
||||
|
||||
$this->user = User::create([
|
||||
'public_id' => 'phase7-user-001',
|
||||
'name' => 'Phase7 User',
|
||||
'email' => 'phase7@example.com',
|
||||
]);
|
||||
|
||||
$this->organization = Organization::create([
|
||||
'owner_ref' => $this->user->public_id,
|
||||
'name' => 'Phase7 Org',
|
||||
'slug' => 'phase7-org',
|
||||
'settings' => ['onboarded' => true, 'badge_expiry_hours' => 8],
|
||||
]);
|
||||
|
||||
Member::create([
|
||||
'owner_ref' => $this->user->public_id,
|
||||
'organization_id' => $this->organization->id,
|
||||
'user_ref' => $this->user->public_id,
|
||||
'role' => 'org_admin',
|
||||
]);
|
||||
|
||||
Branch::create([
|
||||
'owner_ref' => $this->user->public_id,
|
||||
'organization_id' => $this->organization->id,
|
||||
'name' => 'HQ',
|
||||
'is_active' => true,
|
||||
]);
|
||||
|
||||
Host::create([
|
||||
'owner_ref' => $this->user->public_id,
|
||||
'organization_id' => $this->organization->id,
|
||||
'name' => 'Lobby Host',
|
||||
'is_available' => true,
|
||||
]);
|
||||
|
||||
$this->deviceToken = 'kiosk-test-token-'.str_repeat('x', 32);
|
||||
}
|
||||
|
||||
public function test_admin_can_register_kiosk_device(): void
|
||||
{
|
||||
$this->actingAs($this->user)
|
||||
->post(route('frontdesk.devices.store'), [
|
||||
'name' => 'Lobby Kiosk',
|
||||
'type' => 'kiosk',
|
||||
])
|
||||
->assertRedirect(route('frontdesk.devices.index'));
|
||||
|
||||
$device = Device::first();
|
||||
$this->assertSame('kiosk', $device->type);
|
||||
$this->assertNotEmpty($device->device_token);
|
||||
}
|
||||
|
||||
public function test_kiosk_device_page_works_without_auth(): void
|
||||
{
|
||||
$device = $this->createKioskDevice();
|
||||
|
||||
$this->get(route('frontdesk.kiosk.device', $device->device_token))
|
||||
->assertOk()
|
||||
->assertSee('Visitor Check-in');
|
||||
|
||||
$this->assertTrue($device->fresh()->isOnline());
|
||||
}
|
||||
|
||||
public function test_kiosk_device_can_check_in_visitor(): void
|
||||
{
|
||||
$device = $this->createKioskDevice();
|
||||
$host = Host::first();
|
||||
|
||||
$this->postJson(route('frontdesk.kiosk.device.check-in', $device->device_token), [
|
||||
'full_name' => 'Kiosk Guest',
|
||||
'host_id' => $host->id,
|
||||
'visitor_type' => 'visitor',
|
||||
'policies_accepted' => 1,
|
||||
])->assertOk()
|
||||
->assertJsonPath('visit.visitor_name', 'Kiosk Guest');
|
||||
|
||||
$visit = Visit::first();
|
||||
$this->assertSame(Visit::STATUS_CHECKED_IN, $visit->status);
|
||||
$this->assertSame($device->branch_id, $visit->branch_id);
|
||||
}
|
||||
|
||||
public function test_device_heartbeat_api_marks_online(): void
|
||||
{
|
||||
$device = $this->createKioskDevice(['status' => 'offline', 'last_online_at' => null]);
|
||||
|
||||
$this->postJson('/api/devices/heartbeat', [], [
|
||||
'X-Device-Token' => $device->device_token,
|
||||
])->assertOk()
|
||||
->assertJsonPath('status', 'online');
|
||||
|
||||
$this->assertTrue($device->fresh()->isOnline());
|
||||
}
|
||||
|
||||
public function test_mark_devices_offline_command(): void
|
||||
{
|
||||
Carbon::setTestNow(now());
|
||||
|
||||
$device = $this->createKioskDevice([
|
||||
'status' => 'online',
|
||||
'last_online_at' => now()->subMinutes(30),
|
||||
]);
|
||||
|
||||
$this->artisan('frontdesk:mark-devices-offline')->assertSuccessful();
|
||||
|
||||
$this->assertSame('offline', $device->fresh()->status);
|
||||
|
||||
Carbon::setTestNow();
|
||||
}
|
||||
|
||||
public function test_invalid_device_token_returns_not_found(): void
|
||||
{
|
||||
$this->get(route('frontdesk.kiosk.device', 'invalid-token'))
|
||||
->assertNotFound();
|
||||
}
|
||||
|
||||
/** @param array<string, mixed> $overrides */
|
||||
protected function createKioskDevice(array $overrides = []): Device
|
||||
{
|
||||
return Device::create(array_merge([
|
||||
'owner_ref' => $this->user->public_id,
|
||||
'organization_id' => $this->organization->id,
|
||||
'branch_id' => Branch::first()->id,
|
||||
'name' => 'Test Kiosk',
|
||||
'type' => 'kiosk',
|
||||
'status' => 'offline',
|
||||
'device_token' => $this->deviceToken,
|
||||
'config' => ['mode' => 'self_service'],
|
||||
], $overrides));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user