feat: add landing page templates and registration modal
- Implemented header and hero section in _header.html.twig and _hero_art.html.twig. - Created a pre-registration modal in _reg_modal.html.twig with form fields and validation. - Added page scripts for dynamic behavior and interaction in _page_scripts.html.twig. - Developed landing page structure in landing.html.twig, integrating header, footer, and modal. - Introduced tests for landing page rendering and registry validation in LandingPageTest.php and LandingRegistryTest.php.
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tests\Shared;
|
||||
|
||||
use App\Shared\Landing\LandingRegistry;
|
||||
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
||||
/**
|
||||
* صفحات فرود واقعاً رندر میشوند و متادیتای هرکدام مالِ خودش است.
|
||||
*
|
||||
* روت `/{slug}` هر مسیر تکبخشی را میگیرد، پس اینجا هم بررسی میشود که صفحهٔ اصلی و
|
||||
* مسیرهای موجود را نخورده باشد.
|
||||
*/
|
||||
class LandingPageTest extends WebTestCase
|
||||
{
|
||||
private KernelBrowser $client;
|
||||
private LandingRegistry $registry;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->client = static::createClient();
|
||||
$this->registry = new LandingRegistry();
|
||||
}
|
||||
|
||||
private function html(string $path): string
|
||||
{
|
||||
$this->client->request('GET', $path);
|
||||
|
||||
return $this->client->getResponse()->getContent();
|
||||
}
|
||||
|
||||
public function testEveryLandingRenders(): void
|
||||
{
|
||||
foreach ($this->registry->all() as $slug => $page) {
|
||||
$html = $this->html('/' . $slug);
|
||||
|
||||
self::assertSame(200, $this->client->getResponse()->getStatusCode(), "صفحهٔ «{$slug}» باز نشد");
|
||||
self::assertStringContainsString('<h1 class="reveal">' . $page->h1 . '</h1>', $html);
|
||||
self::assertStringContainsString('<title>' . $page->metaTitle . '</title>', $html);
|
||||
self::assertStringContainsString('content="' . $page->metaDescription . '"', $html);
|
||||
}
|
||||
}
|
||||
|
||||
public function testCanonicalPointsAtTheSamePage(): void
|
||||
{
|
||||
foreach (array_keys($this->registry->all()) as $slug) {
|
||||
$html = $this->html('/' . $slug);
|
||||
|
||||
self::assertMatchesRegularExpression(
|
||||
'~<link rel="canonical" href="[^"]+/' . preg_quote($slug, '~') . '"/>~u',
|
||||
$html,
|
||||
"canonical صفحهٔ «{$slug}» به خودش اشاره نمیکند",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function testUnknownSlugIsNotFound(): void
|
||||
{
|
||||
$this->client->request('GET', '/یک-اسلاگ-که-وجود-ندارد');
|
||||
|
||||
self::assertSame(404, $this->client->getResponse()->getStatusCode());
|
||||
}
|
||||
|
||||
/** روت catch-all نباید صفحهٔ اصلی را بخورد. */
|
||||
public function testHomePageStillWorks(): void
|
||||
{
|
||||
$html = $this->html('/');
|
||||
|
||||
self::assertSame(200, $this->client->getResponse()->getStatusCode());
|
||||
self::assertStringContainsString('هوشمند، سریع و', $html);
|
||||
}
|
||||
|
||||
public function testExistingRoutesAreNotShadowed(): void
|
||||
{
|
||||
foreach (['/sitemap.xml', '/health'] as $path) {
|
||||
$this->client->request('GET', $path);
|
||||
self::assertSame(200, $this->client->getResponse()->getStatusCode(), "{$path} گرفته شد");
|
||||
}
|
||||
}
|
||||
|
||||
public function testSitemapListsHomeAndEveryLanding(): void
|
||||
{
|
||||
$xml = $this->html('/sitemap.xml');
|
||||
$doc = new \SimpleXMLElement($xml);
|
||||
|
||||
self::assertCount(8, $doc->url, 'sitemap باید خانه و هفت لندینگ را داشته باشد');
|
||||
|
||||
foreach (array_keys($this->registry->all()) as $slug) {
|
||||
self::assertStringContainsString(rawurlencode($slug), $xml, "«{$slug}» در sitemap نیست");
|
||||
}
|
||||
}
|
||||
|
||||
/** بدون لینک داخلی، صفحات فقط از sitemap دیده میشوند. */
|
||||
public function testFooterLinksToEveryLandingOnEveryPage(): void
|
||||
{
|
||||
foreach (['/', '/' . LandingRegistry::CRM] as $path) {
|
||||
$html = $this->html($path);
|
||||
|
||||
foreach (array_keys($this->registry->all()) as $slug) {
|
||||
self::assertStringContainsString('href="/' . $slug . '"', $html, "لینک «{$slug}» در {$path} نیست");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function testStructuredDataIsValidJson(): void
|
||||
{
|
||||
foreach (array_keys($this->registry->all()) as $slug) {
|
||||
$html = $this->html('/' . $slug);
|
||||
|
||||
preg_match('~<script type="application/ld\+json">(.*?)</script>~s', $html, $m);
|
||||
self::assertNotEmpty($m, "صفحهٔ «{$slug}» بلاک JSON-LD ندارد");
|
||||
|
||||
$data = json_decode(html_entity_decode($m[1]), true, flags: JSON_THROW_ON_ERROR);
|
||||
$types = array_column($data['@graph'], '@type');
|
||||
|
||||
self::assertContains('SoftwareApplication', $types);
|
||||
self::assertContains('BreadcrumbList', $types);
|
||||
self::assertContains('FAQPage', $types);
|
||||
}
|
||||
}
|
||||
|
||||
/** تم مشترک است، پس همان CSS صفحهٔ اصلی باید بارگذاری شود. */
|
||||
public function testLandingUsesTheHomepageTheme(): void
|
||||
{
|
||||
preg_match_all('~href="(/build/[^"]+\.css)"~', $this->html('/'), $home);
|
||||
preg_match_all('~href="(/build/[^"]+\.css)"~', $this->html('/' . LandingRegistry::BEAUTY), $landing);
|
||||
|
||||
self::assertNotEmpty($home[1]);
|
||||
self::assertSame($home[1], $landing[1], 'لندینگ باید همان CSS صفحهٔ اصلی را بارگذاری کند');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user