withoutMiddleware([ VerifyCsrfToken::class, \Illuminate\Session\Middleware\AuthenticateSession::class, ]); } // ─── /@handle alias ───────────────────────────── public function test_at_handle_url_opens_the_matching_channel(): void { $user = User::factory()->create([ 'name' => 'Handle Test', 'username' => 'handletest-'.substr(bin2hex(random_bytes(3)), 0, 6), ]); $r = $this->get('/@' . $user->username)->assertOk(); $r->assertSee('Handle Test', false); } public function test_at_handle_rejects_invalid_characters(): void { // Space in the handle must not match the /@ route. $this->get('/@not valid')->assertStatus(404); } // ─── Preview-as-visitor hides composer ────────── public function test_preview_as_visitor_hides_the_wall_composer(): void { $user = User::factory()->create([ 'username' => 'preview-'.substr(bin2hex(random_bytes(3)), 0, 6), ]); $this->actingAs($user); // The composer form carries id="postForm" and action pointing at // posts.store — specific enough that we don't collide with the // "ch-composer-*" literals that appear in inline JS strings. $owner = $this->get('/channel/' . $user->username)->getContent(); $this->assertStringContainsString('id="postForm"', $owner, 'Owner should see the composer form in normal view.'); $preview = $this->get('/channel/' . $user->username . '?preview=1')->getContent(); $this->assertStringNotContainsString('id="postForm"', $preview, 'Preview-as-visitor must hide the composer form.'); } // ─── Playlist card: pluralise + hide stray "0.0" ── public function test_playlist_card_pluralises_videos_and_hides_zero_views(): void { $owner = User::factory()->create([ 'username' => 'pl-'.substr(bin2hex(random_bytes(3)), 0, 6), ]); $this->actingAs($owner); $pl = Playlist::create([ 'user_id' => $owner->id, 'name' => 'Empty Playlist', 'visibility' => 'public', 'share_token'=> bin2hex(random_bytes(8)), ]); $html = $this->get('/channel/' . $owner->username)->getContent(); // The specific bug: the view-count row ends with // ` 0.0` // for a zero-view playlist. The fix hides the whole row for zero // views, so the "bi-eye ...0.0" sequence should never appear. $this->assertDoesNotMatchRegularExpression( '/bi-eye[^<]{0,200}0\.0/', $html, 'Playlist meta must not emit "bi-eye … 0.0" for zero-view playlists.' ); // Plural must switch to singular for 1 video. Never "1 videos". $this->assertDoesNotMatchRegularExpression('/\b1 videos\b/i', $html); } }