test(polish): match channel row, nested-reply, cursor paginator, hotkeys
Four tests covering the post-audit polish commits: - Match watch page renders the shared .channel-row component. - Reply-to-reply button carries data-parent-id and data-handle so the JS can prefill "@author " when the parent reply form opens. - liked() controller returns a CursorPaginator instance (controller introspection — avoids a 400 KB view render per assertion). - video-player component ships the ">" / "<" playback-rate hotkey. Also cleans up a stale ->onEachSide()->links() call in user/liked.blade that would blow up now that the controller returns a CursorPaginator (which doesn't support onEachSide). Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
1 parent
341e94a4f8
commit
73de5bc97e
2 files changed
+167
-1
No files matched your search
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Http\Middleware\VerifyCsrfToken;
|
||||
use App\Models\Comment;
|
||||
use App\Models\SportsMatch;
|
||||
use App\Models\User;
|
||||
use App\Models\Video;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* Post-audit polish — the deferred items we tackled in bulk after Phase 7:
|
||||
* match channel row, read-more clamp, nested-reply prefill, player hotkeys,
|
||||
* cursor pagination on /liked and /history.
|
||||
*/
|
||||
class PostAuditPolishTest 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,
|
||||
]);
|
||||
}
|
||||
|
||||
// ─── Match page: channel row ─────────────────────
|
||||
|
||||
public function test_match_watch_page_renders_the_channel_row(): void
|
||||
{
|
||||
$owner = $this->makeUser('match-owner');
|
||||
$video = Video::create([
|
||||
'user_id' => $owner->id,
|
||||
'title' => 'MatchTitle',
|
||||
'description' => '',
|
||||
'filename' => 'users/x/sports/y/video.mp4',
|
||||
'path' => 'users/x/sports/y/video.mp4',
|
||||
'type' => 'match',
|
||||
'visibility' => 'public',
|
||||
'status' => 'ready',
|
||||
'share_token' => bin2hex(random_bytes(8)),
|
||||
]);
|
||||
// Minimal sports_match so the match blade renders without null checks exploding.
|
||||
SportsMatch::create([
|
||||
'video_id' => $video->id,
|
||||
'user_id' => $owner->id,
|
||||
'title' => 'MatchTitle',
|
||||
'participants' => [],
|
||||
'sport' => 'karate',
|
||||
]);
|
||||
|
||||
$html = $this->get(route('videos.show', $video))->getContent();
|
||||
|
||||
$this->assertStringContainsString('channel-row', $html,
|
||||
'Match watch page must render the shared channel row component.');
|
||||
}
|
||||
|
||||
// ─── Comment reply: nested handle button present ──
|
||||
|
||||
public function test_reply_to_reply_button_carries_data_handle(): void
|
||||
{
|
||||
$owner = $this->makeUser('replyowner');
|
||||
$this->actingAs($owner);
|
||||
$video = Video::create([
|
||||
'user_id' => $owner->id,
|
||||
'title' => 'Vid',
|
||||
'description'=> '',
|
||||
'filename' => 'users/x/videos/y/video.mp4',
|
||||
'path' => 'users/x/videos/y/video.mp4',
|
||||
'type' => 'generic',
|
||||
'visibility' => 'public',
|
||||
'status' => 'ready',
|
||||
'share_token'=> bin2hex(random_bytes(8)),
|
||||
]);
|
||||
$parent = Comment::create([
|
||||
'user_id' => $owner->id,
|
||||
'video_id' => $video->id,
|
||||
'body' => 'top',
|
||||
]);
|
||||
$replier = $this->makeUser('replier');
|
||||
Comment::create([
|
||||
'user_id' => $replier->id,
|
||||
'video_id' => $video->id,
|
||||
'parent_id' => $parent->id,
|
||||
'body' => 'nested',
|
||||
]);
|
||||
|
||||
$html = view('components.video-comments', ['video' => $video])->render();
|
||||
|
||||
// The nested reply trigger must carry the reply author's handle so the
|
||||
// JS can prefill "@handle " when the parent's reply form opens.
|
||||
$this->assertMatchesRegularExpression(
|
||||
'/_comment-reply-nested-trigger[^"]*"\s+data-parent-id="' . $parent->id . '"\s+data-handle="' . preg_quote($replier->username, '/') . '"/',
|
||||
$html
|
||||
);
|
||||
}
|
||||
|
||||
// ─── Liked feed: cursor pagination ────────────────
|
||||
|
||||
public function test_liked_controller_returns_a_cursor_paginator(): void
|
||||
{
|
||||
// The controller introspection is enough to confirm the pagination
|
||||
// mode — the full HTML path depends on view rendering that costs
|
||||
// 400 KB per test and isn't the behaviour we're asserting on.
|
||||
$user = $this->makeUser('liker');
|
||||
$this->actingAs($user);
|
||||
|
||||
$route = app('router')->getRoutes()->getByName('liked');
|
||||
[$class, $method] = explode('@', $route->getActionName());
|
||||
$controller = app($class);
|
||||
|
||||
$response = $controller->$method();
|
||||
$videos = $response->getData()['videos'] ?? null;
|
||||
|
||||
$this->assertInstanceOf(
|
||||
\Illuminate\Pagination\CursorPaginator::class,
|
||||
$videos,
|
||||
'liked() must return a CursorPaginator instance.'
|
||||
);
|
||||
}
|
||||
|
||||
// ─── Player hotkey code is present ────────────────
|
||||
|
||||
public function test_player_component_handles_shift_dot_hotkey(): void
|
||||
{
|
||||
// The player component accepts a $video context — pass a bare
|
||||
// record so the view renders.
|
||||
$u = $this->makeUser('p');
|
||||
$v = Video::create([
|
||||
'user_id' => $u->id,
|
||||
'title' => 't',
|
||||
'description'=> '',
|
||||
'filename' => 'users/x/videos/y/video.mp4',
|
||||
'path' => 'users/x/videos/y/video.mp4',
|
||||
'type' => 'generic',
|
||||
'visibility' => 'public',
|
||||
'status' => 'ready',
|
||||
'share_token'=> bin2hex(random_bytes(8)),
|
||||
]);
|
||||
$html = view('components.video-player', ['video' => $v])->render();
|
||||
|
||||
$this->assertStringContainsString("case '>':", $html);
|
||||
$this->assertStringContainsString("case '<':", $html);
|
||||
$this->assertStringContainsString('video.playbackRate', $html);
|
||||
}
|
||||
|
||||
// ─── Helpers ─────────────────────────────────────
|
||||
|
||||
private function makeUser(string $prefix): User
|
||||
{
|
||||
return User::factory()->create([
|
||||
'username' => $prefix.'-'.substr(bin2hex(random_bytes(4)), 0, 6),
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user