Every landing page was listed in the footer, so adding keyword clusters made that one column taller than the rest of the footer put together. It now lists six — the head terms and the two biggest specialties — and the rest stay reachable through the "other solutions" block each page already renders. That trade only holds if nothing falls out of the link graph, so the old test asserting "the footer links to every page" is replaced by one that walks the related-page graph from the footer links and fails when any page is not reachable. Physiotherapy was the one page that would have been orphaned; the polyclinic page now links to it. The related-solutions heading said "for your trade", which reads oddly for the clinics it is addressing, and its cards were left-aligned in a centered section. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
109 lines
5.1 KiB
PHP
109 lines
5.1 KiB
PHP
<?php
|
|
|
|
namespace App\Tests\Shared;
|
|
|
|
use App\Shared\Landing\LandingPage;
|
|
use App\Shared\Landing\LandingRegistry;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
/**
|
|
* قواعدی که اگر بشکنند، صفحههای فرود بهجای کمک به رتبه، به هم آسیب میزنند:
|
|
* عنوان یا h1 تکراری یعنی محتوای تکراری، و توضیحات بیرون از بازهٔ استاندارد در
|
|
* نتایج جستجو بریده میشود.
|
|
*/
|
|
class LandingRegistryTest extends TestCase
|
|
{
|
|
private LandingRegistry $registry;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->registry = new LandingRegistry();
|
|
}
|
|
|
|
public function testEverySlugIsRegistered(): void
|
|
{
|
|
$slugs = array_keys($this->registry->all());
|
|
|
|
// تعداد صفحهها با هر خوشهٔ کلیدواژهٔ تازه بالا میرود، پس عدد ثابت اینجا فقط
|
|
// یک تستِ شکننده میسازد. آنچه باید ثابت بماند این است که هر ثابتِ کلاس
|
|
// واقعاً صفحهای دارد — ثابتی که ساخته نشده باشد، لینک داخلیِ ۴۰۴ میسازد.
|
|
// فقط ثابتهای عمومی: اسلاگها همانهایند و ثابتهای داخلی (مثل فهرست فوتر)
|
|
// صفحه نیستند.
|
|
foreach ((new \ReflectionClass(LandingRegistry::class))->getReflectionConstants() as $constant) {
|
|
if (!$constant->isPublic()) {
|
|
continue;
|
|
}
|
|
|
|
self::assertContains($constant->getValue(), $slugs, "ثابت {$constant->getName()} صفحهای ندارد");
|
|
}
|
|
|
|
self::assertCount(count($slugs), array_unique($slugs));
|
|
}
|
|
|
|
public function testUnknownSlugReturnsNull(): void
|
|
{
|
|
self::assertNull($this->registry->find('یک-اسلاگ-ناموجود'));
|
|
}
|
|
|
|
public function testFindReturnsTheMatchingPage(): void
|
|
{
|
|
$page = $this->registry->find(LandingRegistry::DENTAL);
|
|
|
|
self::assertInstanceOf(LandingPage::class, $page);
|
|
self::assertSame(LandingRegistry::DENTAL, $page->slug);
|
|
}
|
|
|
|
public function testTitlesAndHeadingsAreUnique(): void
|
|
{
|
|
$titles = array_map(static fn (LandingPage $p): string => $p->metaTitle, $this->registry->all());
|
|
$h1s = array_map(static fn (LandingPage $p): string => $p->h1, $this->registry->all());
|
|
|
|
$descriptions = array_map(static fn (LandingPage $p): string => $p->metaDescription, $this->registry->all());
|
|
|
|
self::assertCount(count($titles), array_unique($titles), 'عنوان تکراری یعنی محتوای تکراری');
|
|
self::assertCount(count($h1s), array_unique($h1s), 'h1 تکراری یعنی محتوای تکراری');
|
|
// توضیحات تکراری همان پیام را میدهد: دو صفحه که یک چیز را میگویند.
|
|
self::assertCount(count($descriptions), array_unique($descriptions), 'توضیحات تکراری یعنی محتوای تکراری');
|
|
}
|
|
|
|
/** توضیحات کوتاهتر از ۱۲۰ فرصت را هدر میدهد و بلندتر از ۱۷۰ در نتایج بریده میشود. */
|
|
public function testMetaDescriptionLengthIsWithinSearchLimits(): void
|
|
{
|
|
foreach ($this->registry->all() as $slug => $page) {
|
|
$length = mb_strlen($page->metaDescription);
|
|
self::assertGreaterThanOrEqual(120, $length, "توضیحات «{$slug}» کوتاه است");
|
|
self::assertLessThanOrEqual(170, $length, "توضیحات «{$slug}» بلند است");
|
|
}
|
|
}
|
|
|
|
public function testEveryPageHasContentToRender(): void
|
|
{
|
|
foreach ($this->registry->all() as $slug => $page) {
|
|
self::assertNotSame('', trim($page->lead), "lead «{$slug}» خالی است");
|
|
self::assertGreaterThanOrEqual(4, count($page->features), "امکانات «{$slug}» کم است");
|
|
self::assertGreaterThanOrEqual(3, count($page->faq), "پرسشهای «{$slug}» کم است");
|
|
}
|
|
}
|
|
|
|
/** لینک داخلی به اسلاگی که وجود ندارد یعنی ۴۰۴ داخل خود سایت. */
|
|
public function testRelatedLinksPointAtRealPages(): void
|
|
{
|
|
$known = array_keys($this->registry->all());
|
|
|
|
foreach ($this->registry->all() as $slug => $page) {
|
|
self::assertNotContains($slug, $page->related, "«{$slug}» به خودش لینک داده");
|
|
foreach ($page->related as $target) {
|
|
self::assertContains($target, $known, "«{$slug}» به «{$target}» لینک داده که وجود ندارد");
|
|
}
|
|
}
|
|
}
|
|
|
|
public function testSlugsCarryTheKeywordAndNoSpaces(): void
|
|
{
|
|
foreach (array_keys($this->registry->all()) as $slug) {
|
|
self::assertStringNotContainsString(' ', $slug, 'اسلاگ نباید فاصله داشته باشد');
|
|
self::assertSame(trim($slug, '-'), $slug, 'اسلاگ نباید با خط تیره شروع یا تمام شود');
|
|
}
|
|
}
|
|
}
|