client = static::createClient(); $this->bootDatabase(); $this->bootFaker(); $this->getFaker()->unique(); } public function testPostListed(): void { $posts = $this->createTestPosts(); $crawler = $this->client->request('GET', '/posts/1'); $this->assertResponseIsSuccessful(); $this->assertSelectorCount(3, '.t-detail-a'); // 3 posts are listed $displayedPosts = array_reverse(array_slice($posts, count($posts) - 3, 3)); // in ORDER by ID DESC /** * @var Post $post */ foreach ($displayedPosts as $i => $post) { // check texts $this->assertSelectorTextContains('.t-post-detail:nth-child(' . ($i + 1) . ') .t-post-title', $this->truncateToWholeWords($post->title, 70)); $text = $crawler->filter('.t-post-detail:nth-child(' . ($i + 1) . ') .t-post-title')->text(); $this->assertLessThan(83, strlen($text), "Text $text too long"); // 80 + 3 extra characters for ellipsis $this->assertSelectorTextContains('.t-post-detail:nth-child(' . ($i + 1) . ') .t-post-body', $this->truncateToWholeWords($post->body, 70)); $text = $crawler->filter('.t-post-detail:nth-child(' . ($i + 1) . ') .t-post-body')->text(); $this->assertLessThan(83, strlen($text), "Text $text too long"); // 80 + 3 extra characters for ellipsis } } public function testPagination(): void { $posts = $this->createTestPosts(); $crawler = $this->client->request('GET', '/posts/1'); $this->assertResponseIsSuccessful(); $this->assertSelectorCount(4 /* 3 -> normal, 1 -> last page */, '.t-pagination .t-page-item'); $crawler = $this->client->click($crawler->filter('.t-pagination .t-page-item:nth-child(3) .t-page-link')->link()); $this->assertSelectorCount(5 /* 3 -> normal, 2 -> first page, last page */, '.t-pagination .t-page-item'); } public function testGoToNonExistentPage(): void { $this->createTestPosts(); $this->client->request('GET', '/posts/999999'); $this->assertResponseStatusCodeSame(302); $this->assertResponseHeaderSame('Location', '/posts/10' /* last page (30 posts /3 per page) */); } public function testGoToPageZero(): void { $this->createTestPosts(); $this->client->request('GET', '/posts/0'); $this->assertResponseStatusCodeSame(302); $this->assertResponseHeaderSame('Location', '/posts' /* go to first page */); } public function testGoToDefault(): void { $this->createTestPosts(); $this->client->request('GET', '/'); $this->assertResponseIsSuccessful(); $this->assertSelectorCount(3, '.t-detail-a'); // 3 posts are listed } private function truncateToWholeWords(string $string, int $length): string { if (strlen($string) <= $length) { return $string; } // Find the last space within the allowed length $truncated = substr($string, 0, $length); $lastSpace = strrpos($truncated, ' '); // If there's no space, truncate to the exact length if ($lastSpace === false) { return substr($truncated, 0, $length); } return substr($truncated, 0, $lastSpace); } /** * @return Post[] */ private function createTestPosts(): array { $posts = []; for ($i = 1; $i <= 30; $i++) { $posts[] = $this->createPost($i); } return $posts; } }