Toolvana: production-ready media tools platform (CodeIgniter 4)

- 134-tool registry with programmatic SEO (unique titles/H1/descriptions,
  JSON-LD graphs, sitemap index, canonical 301 enforcement via required filter)
- DB-backed job queue (SKIP LOCKED) with drivers: Ffmpeg, Images (GD),
  Pdf (qpdf/gs/poppler), Youtube (thumbnails), Qr (server-side PNG)
- Security: SSRF guard, MIME validation, rate limits, API-key auth,
  bcrypt admin login, security headers
- Admin panel: dashboard, tools/categories/guides CRUD, SEO audit,
  analytics, job inspector with retry, system health, feature flags
- Docker deployment (nginx + web/api FPM pools + scalable workers),
  PHPUnit suite (19 tests / 1139 assertions), PWA manifest + service worker
This commit is contained in:
deepseek
2026-08-23 07:10:30 +00:00
commit beaf0e1f37
217 changed files with 19619 additions and 0 deletions
+126
View File
@@ -0,0 +1,126 @@
<?php
declare(strict_types=1);
namespace Tests\Feature;
use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\FeatureTestTrait;
/**
* SEO contract tests: every indexable page must render complete,
* crawlable HTML on the FIRST response — no JS required.
*
* These run against the test database (migrated + seeded by setUp).
*/
final class SeoPagesTest extends CIUnitTestCase
{
use FeatureTestTrait;
public static function setUpBeforeClass(): void
{
parent::setUpBeforeClass();
// migrate + seed the test database once (idempotent)
try {
command('migrate --all');
command('db:seed InitialSeeder');
} catch (\Throwable $e) {
fwrite(STDERR, 'Test DB bootstrap: ' . $e->getMessage() . "\n");
}
}
private function get(string $page): \CodeIgniter\Test\TestResponse
{
return $this->call('get', $page);
}
public function testToolPageRendersFullSeoContract(): void
{
$response = $this->get('/youtube-to-mp3');
$response->assertStatus(200);
$html = (string) $response->getBody();
// canonical, title, description, OG
$this->assertMatchesRegularExpression('#<link rel="canonical" href="https?://[^"]+/youtube-to-mp3">#', $html);
$this->assertMatchesRegularExpression('/<title>[^<]+<\/title>/', $html);
$this->assertStringContainsString('name="description"', $html);
$this->assertStringContainsString('property="og:title"', $html);
$this->assertStringContainsString('name="twitter:card" content="summary_large_image"', $html);
// structured data: FAQPage + BreadcrumbList + WebApplication
$jsonLd = '';
if (preg_match('/<script type="application\/ld\+json">(.*?)<\/script>/s', $html, $m)) {
$jsonLd = $m[1];
}
$this->assertNotSame('', $jsonLd, 'JSON-LD block missing');
foreach (['BreadcrumbList', 'WebApplication', 'FAQPage'] as $type) {
$this->assertStringContainsString('"' . $type . '"', $jsonLd, "{$type} missing from JSON-LD");
}
// content in first response: H1, how-to steps, FAQ questions visible
$this->assertStringContainsString('<h1>', $html);
$this->assertStringContainsString('Frequently asked questions', $html);
$this->assertStringContainsString('Related tools', $html);
$this->assertStringContainsString('breadcrumbs', $html);
// robots meta allows indexing
$this->assertStringContainsString('content="index, follow', $html);
}
public function testCategoryAndHomepageAreIndexable(): void
{
foreach (['/', '/youtube-tools', '/tools'] as $page) {
$html = (string) $this->get($page)->getBody();
$this->assertStringContainsString('rel="canonical"', $html, "canonical missing on {$page}");
$this->assertStringContainsString('index, follow', $html, "robots meta wrong on {$page}");
}
}
public function testSearchIsNoindexed(): void
{
$html = (string) $this->get('/search?q=mp3')->getBody();
$this->assertStringContainsString('noindex', $html);
}
public function testSitemapsContainOnlyCanonicalUrls(): void
{
$index = (string) $this->get('/sitemap.xml')->getBody();
$this->assertStringContainsString('sitemapindex', $index);
$this->assertStringContainsString('sitemap-tools-1.xml', $index);
$this->assertStringContainsString('sitemap-guides.xml', $index);
$tools = (string) $this->get('/sitemap-tools-1.xml')->getBody();
$this->assertStringContainsString('/youtube-to-mp3</loc>', $tools);
$this->assertDoesNotMatchRegularExpression('#<loc>[^<]*/(api/|admin|download/|search\?)#', $tools, 'Non-indexable URL leaked into sitemap');
$categories = (string) $this->get('/sitemap-categories.xml')->getBody();
$this->assertStringContainsString('/youtube-tools</loc>', $categories);
}
public function testRobotsTxtBlocksProcessingEndpoints(): void
{
$body = (string) $this->get('/robots.txt')->getBody();
$this->assertStringContainsString('Disallow: /api/', $body);
$this->assertStringContainsString('Disallow: /download/', $body);
$this->assertStringContainsString('Disallow: /admin', $body);
$this->assertStringContainsString('Sitemap:', $body);
}
public function testUppercaseUrl301RedirectsToCanonical(): void
{
$this->get('/YouTube-To-MP3')->assertStatus(301);
}
public function testUnknownSlugReturnsUseful404(): void
{
$result = $this->get('/this-tool-does-not-exist');
$result->assertStatus(404);
$html = (string) $result->getBody();
$this->assertStringContainsString('Tool not found', $html);
$this->assertStringContainsString('Popular tools', $html, '404 page must link popular tools');
}
}