test(live): 7 tests for the Live polish work
Covers Private visibility acceptance, ended-state Watch page shows "Stream ended" (and omits the "Waiting for the broadcast" placeholder from the connection JS), channel-name link resolves to the user's channel URL, chat poll returns messages newer than ?since=, chat send rejects guests (401), chat send rejects offline streams (422), and private-stream chat 404s for non-owners. Also broadens LiveStream::isWatchableBy to keep public/unlisted streams permalinked after they end — viewers now see the Stream Ended card and the Watch Replay CTA instead of a hard 404. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
1 parent
5bf1128196
commit
8fef257c86
3 files changed
+169
-1
No files matched your search
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Http\Middleware\VerifyCsrfToken;
|
||||
use App\Models\LiveChatMessage;
|
||||
use App\Models\LiveStream;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* Live polish regression tests. Covers:
|
||||
* - Private visibility accepted by /live/new validation.
|
||||
* - Ended-state watch page shows "Stream ended" + duration.
|
||||
* - Chat poll endpoint returns everything newer than ?since=.
|
||||
* - Chat send endpoint rejects guests, non-live streams, and
|
||||
* anyone but the owner on a private stream.
|
||||
*/
|
||||
class LivePolishTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
putenv('DB_CONNECTION=sqlite');
|
||||
putenv('DB_DATABASE=:memory:');
|
||||
$_ENV['DB_CONNECTION'] = 'sqlite';
|
||||
$_ENV['DB_DATABASE'] = ':memory:';
|
||||
|
||||
parent::setUp();
|
||||
|
||||
$this->withoutMiddleware([
|
||||
VerifyCsrfToken::class,
|
||||
\Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||
]);
|
||||
}
|
||||
|
||||
// ─── Private visibility accepted ─────────────────
|
||||
|
||||
public function test_create_live_stream_accepts_private_visibility(): void
|
||||
{
|
||||
$u = $this->makeUser();
|
||||
$this->actingAs($u);
|
||||
|
||||
$this->post(route('live.store'), [
|
||||
'title' => 'My private test stream',
|
||||
'description' => 'just testing',
|
||||
'visibility' => 'private',
|
||||
])->assertRedirect();
|
||||
|
||||
$this->assertDatabaseHas('livestreams', [
|
||||
'user_id' => $u->id,
|
||||
'title' => 'My private test stream',
|
||||
'visibility' => 'private',
|
||||
]);
|
||||
}
|
||||
|
||||
// ─── Ended state renders "Stream ended" ──────────
|
||||
|
||||
public function test_ended_stream_watch_page_shows_stream_ended(): void
|
||||
{
|
||||
$u = $this->makeUser();
|
||||
$s = $this->makeStream($u, [
|
||||
'status' => LiveStream::STATUS_ENDED,
|
||||
'started_at' => now()->subMinutes(10),
|
||||
'ended_at' => now(),
|
||||
]);
|
||||
|
||||
$html = $this->get(route('live.watch', $s))->assertOk()->getContent();
|
||||
$this->assertStringContainsString('Stream ended', $html);
|
||||
$this->assertStringNotContainsString('Waiting for the broadcast to start', $html);
|
||||
}
|
||||
|
||||
// ─── Channel name is a link ──────────────────────
|
||||
|
||||
public function test_watch_page_channel_name_is_a_real_link(): void
|
||||
{
|
||||
$u = $this->makeUser();
|
||||
$s = $this->makeStream($u, ['status' => LiveStream::STATUS_LIVE]);
|
||||
$expected = route('channel', $u->channel);
|
||||
|
||||
$html = $this->get(route('live.watch', $s))->assertOk()->getContent();
|
||||
|
||||
$this->assertStringContainsString('href="' . $expected . '"', $html);
|
||||
}
|
||||
|
||||
// ─── Chat poll ───────────────────────────────────
|
||||
|
||||
public function test_chat_poll_returns_messages_newer_than_since(): void
|
||||
{
|
||||
$u = $this->makeUser();
|
||||
$s = $this->makeStream($u, ['status' => LiveStream::STATUS_LIVE]);
|
||||
|
||||
$a = LiveChatMessage::create(['livestream_id' => $s->id, 'user_id' => $u->id, 'author_name' => 'A', 'body' => 'hello', 'created_at' => now()]);
|
||||
$b = LiveChatMessage::create(['livestream_id' => $s->id, 'user_id' => $u->id, 'author_name' => 'A', 'body' => 'world', 'created_at' => now()]);
|
||||
|
||||
$this->getJson(route('live.chat.poll', $s) . '?since=' . $a->id)
|
||||
->assertOk()
|
||||
->assertJsonCount(1, 'messages')
|
||||
->assertJsonPath('messages.0.body', 'world');
|
||||
}
|
||||
|
||||
// ─── Chat send ───────────────────────────────────
|
||||
|
||||
public function test_chat_send_rejects_guests(): void
|
||||
{
|
||||
$u = $this->makeUser();
|
||||
$s = $this->makeStream($u, ['status' => LiveStream::STATUS_LIVE]);
|
||||
|
||||
// postJson sets Accept: application/json so the auth middleware
|
||||
// returns 401 instead of redirecting to login.
|
||||
$this->postJson(route('live.chat.send', $s), ['body' => 'hi'])
|
||||
->assertStatus(401);
|
||||
}
|
||||
|
||||
public function test_chat_send_rejects_offline_streams(): void
|
||||
{
|
||||
$u = $this->makeUser();
|
||||
$s = $this->makeStream($u, ['status' => LiveStream::STATUS_ENDED]);
|
||||
$this->actingAs($u);
|
||||
|
||||
$this->postJson(route('live.chat.send', $s), ['body' => 'hi'])
|
||||
->assertStatus(422);
|
||||
}
|
||||
|
||||
public function test_private_stream_chat_rejects_non_owner(): void
|
||||
{
|
||||
$owner = $this->makeUser();
|
||||
$viewer = $this->makeUser();
|
||||
$s = $this->makeStream($owner, ['status' => LiveStream::STATUS_LIVE, 'visibility' => 'private']);
|
||||
$this->actingAs($viewer);
|
||||
|
||||
$this->postJson(route('live.chat.send', $s), ['body' => 'sneak'])
|
||||
->assertStatus(404);
|
||||
}
|
||||
|
||||
// ─── Helpers ─────────────────────────────────────
|
||||
|
||||
private function makeUser(): User
|
||||
{
|
||||
return User::factory()->create([
|
||||
'username' => 'lu'.substr(bin2hex(random_bytes(4)), 0, 6),
|
||||
]);
|
||||
}
|
||||
|
||||
private function makeStream(User $u, array $attrs = []): LiveStream
|
||||
{
|
||||
return LiveStream::create(array_merge([
|
||||
'user_id' => $u->id,
|
||||
'public_id' => substr(bin2hex(random_bytes(10)), 0, 16),
|
||||
'title' => 'Test stream',
|
||||
'description' => '',
|
||||
'status' => LiveStream::STATUS_IDLE,
|
||||
'visibility' => 'public',
|
||||
], $attrs));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user