Files
ladill-meet/tests/Feature/EventsJoinGateTest.php
T
isaaccladandCursor f9c82d0d1f
Deploy Ladill Meet / deploy (push) Successful in 49s
Grant panelist role to Events speakers on conferences and webinars.
Verify speaker tokens before room-type role resolution so town-hall sessions get panelist access and speaker-panel placement, and skip the waiting room for panelists.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-03 17:56:39 +00:00

253 lines
8.6 KiB
PHP

<?php
namespace Tests\Feature;
use App\Http\Middleware\EnsurePlatformSession;
use App\Models\Member;
use App\Models\Organization;
use App\Models\Room;
use App\Models\Session;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Http;
use Tests\TestCase;
class EventsJoinGateTest extends TestCase
{
use RefreshDatabase;
protected User $user;
protected Organization $organization;
protected function setUp(): void
{
parent::setUp();
$this->withoutMiddleware(EnsurePlatformSession::class);
config([
'meet.events_api_url' => 'https://events.test/api/service/v1',
'meet.events_api_key' => 'test-events-key',
]);
$this->user = User::create([
'public_id' => 'host-events-001',
'name' => 'Event Host',
'email' => 'host@example.com',
]);
$this->organization = Organization::create([
'owner_ref' => $this->user->public_id,
'name' => 'Events Org',
'slug' => 'events-org',
'timezone' => 'UTC',
'settings' => ['onboarded' => true],
]);
Member::create([
'owner_ref' => $this->user->public_id,
'organization_id' => $this->organization->id,
'user_ref' => $this->user->public_id,
'role' => 'owner',
]);
$base = rtrim((string) config('billing.api_url'), '/');
Http::fake([
$base.'/can-afford*' => Http::response(['affordable' => true]),
$base.'/debit' => Http::response(['ok' => true]),
$base.'/balance*' => Http::response(['balance_minor' => 100000]),
'https://events.test/api/service/v1/events/*/verify-registration' => Http::response([
'registration' => [
'attendee_name' => 'Registered Guest',
'attendee_email' => 'guest@example.com',
'badge_code' => 'BADGE123',
],
]),
'https://events.test/api/service/v1/events/*/verify-speaker' => Http::response([
'speaker' => [
'name' => 'Keynote Speaker',
'email' => 'speaker@example.com',
'role' => 'Keynote',
],
]),
]);
}
public function test_events_linked_webinar_shows_registration_gate_for_guest(): void
{
$room = $this->createEventsLinkedRoom('webinar');
$this->get('/r/'.$room->uuid)
->assertOk()
->assertSee('Register for event', false)
->assertSee('Already registered?', false)
->assertDontSee('How should we show your name?', false);
}
public function test_badge_verification_leads_to_display_name_screen(): void
{
$room = $this->createEventsLinkedRoom('webinar');
$this->post('/r/'.$room->uuid.'/verify-badge', ['badge_code' => 'BADGE123'])
->assertRedirect(route('meet.join', $room));
$this->get('/r/'.$room->uuid)
->assertOk()
->assertSee('How should we show your name?', false)
->assertSee('value="Registered Guest"', false)
->assertDontSee('Register for event', false);
}
public function test_verified_guest_can_join_live_webinar_with_display_name_only(): void
{
$room = $this->createEventsLinkedRoom('webinar', [
'settings' => array_merge(config('meet.default_settings'), [
'join_before_host' => true,
'waiting_room' => false,
]),
]);
$session = Session::create([
'owner_ref' => $this->user->public_id,
'room_id' => $room->id,
'media_room_name' => 'room-'.$room->uuid,
'status' => 'live',
'started_at' => now(),
]);
$room->update(['status' => 'live']);
$this->post('/r/'.$room->uuid.'/verify-badge', ['badge_code' => 'BADGE123'])
->assertRedirect(route('meet.join', $room));
$this->post('/r/'.$room->uuid.'/enter', [
'display_name' => 'Registered Guest',
])->assertRedirect(route('meet.room', $session));
$this->assertDatabaseHas('meet_participants', [
'session_id' => $session->id,
'display_name' => 'Registered Guest',
'email' => 'guest@example.com',
'role' => 'attendee',
]);
}
public function test_badge_query_param_auto_verifies_on_join_url(): void
{
$room = $this->createEventsLinkedRoom('webinar');
$this->get('/r/'.$room->uuid.'?badge=BADGE123')
->assertRedirect(route('meet.join', $room));
$this->get('/r/'.$room->uuid)
->assertOk()
->assertSee('How should we show your name?', false);
}
public function test_host_skips_registration_gate(): void
{
$room = $this->createEventsLinkedRoom('webinar');
$this->actingAs($this->user)
->get('/r/'.$room->uuid)
->assertOk()
->assertSee('Joining as', false)
->assertDontSee('Register for event', false);
}
public function test_speaker_token_skips_registration_gate_and_grants_panelist_role(): void
{
$room = $this->createEventsLinkedRoom('webinar', [
'settings' => array_merge(config('meet.default_settings'), [
'join_before_host' => true,
'waiting_room' => false,
]),
]);
$session = Session::create([
'owner_ref' => $this->user->public_id,
'room_id' => $room->id,
'media_room_name' => 'room-'.$room->uuid,
'status' => 'live',
'started_at' => now(),
]);
$room->update(['status' => 'live']);
$this->get('/r/'.$room->uuid.'?speaker=speaker-token-123')
->assertRedirect(route('meet.join', $room));
$this->get('/r/'.$room->uuid)
->assertOk()
->assertSee('How should we show your name?', false)
->assertDontSee('Register for event', false);
$this->post('/r/'.$room->uuid.'/enter', [
'display_name' => 'Keynote Speaker',
])->assertRedirect(route('meet.room', $session));
$this->assertDatabaseHas('meet_participants', [
'session_id' => $session->id,
'display_name' => 'Keynote Speaker',
'email' => 'speaker@example.com',
'role' => 'panelist',
]);
}
public function test_speaker_token_grants_panelist_role_on_events_linked_conference(): void
{
$room = $this->createEventsLinkedRoom('town_hall', [
'settings' => array_merge(config('meet.default_settings'), [
'join_before_host' => true,
'waiting_room' => false,
]),
]);
$session = Session::create([
'owner_ref' => $this->user->public_id,
'room_id' => $room->id,
'media_room_name' => 'room-'.$room->uuid,
'status' => 'live',
'started_at' => now(),
]);
$room->update(['status' => 'live']);
$this->get('/r/'.$room->uuid.'?speaker=speaker-token-123')
->assertRedirect(route('meet.join', $room));
$this->post('/r/'.$room->uuid.'/enter', [
'display_name' => 'Keynote Speaker',
])->assertRedirect(route('meet.room', $session));
$this->assertDatabaseHas('meet_participants', [
'session_id' => $session->id,
'display_name' => 'Keynote Speaker',
'email' => 'speaker@example.com',
'role' => 'panelist',
]);
}
/** @param array<string, mixed> $overrides */
protected function createEventsLinkedRoom(string $type, array $overrides = []): Room
{
return Room::create(array_merge([
'owner_ref' => $this->user->public_id,
'organization_id' => $this->organization->id,
'host_user_ref' => $this->user->public_id,
'title' => 'Linked session',
'type' => $type,
'status' => 'scheduled',
'scheduled_at' => now()->addDay(),
'timezone' => 'UTC',
'settings' => config('meet.default_settings'),
'source' => [
'app' => 'events',
'entity_type' => 'virtual_session',
'entity_id' => 'vs-test',
'event_id' => '42',
'event_title' => 'Summit 2026',
'short_code' => 'summit26',
'registration_url' => 'https://ladl.link/summit26',
],
], $overrides));
}
}