test: add architecture contract tests for layering, sessions, and asset versioning

New contracts enforce repository layer isolation, no HTML in services,
no DB calls in views, module session key prefixes, and asset versioning.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-22 14:15:41 +01:00
parent 555199b217
commit be8bf496cb
5 changed files with 428 additions and 0 deletions

View File

@@ -0,0 +1,74 @@
<?php
namespace MintyPHP\Tests\Architecture;
use PHPUnit\Framework\TestCase;
/**
* All CSS and JS asset references in templates and views must use
* assetVersion() for cache-busting. Bare paths without assetVersion()
* risk serving stale cached assets after deploys.
*
* Excluded: inline scripts, data URIs, external CDN URLs, and empty src attributes.
*/
class AssetVersioningContractTest extends TestCase
{
use ProjectFileAssertionSupport;
/**
* Matches src="..." or href="..." pointing to local .js/.css files
* that are NOT wrapped in assetVersion().
*
* The negative lookbehind ensures we don't flag assetVersion() usages.
* Excludes external URLs (http://, https://, //) and empty attributes.
*/
private const BARE_JS_PATTERN = '/src=["\'](?!https?:\/\/|\/\/)(?!<?php\s+e\(assetVersion)[^"\']*\.js["\']/';
private const BARE_CSS_PATTERN = '/href=["\'](?!https?:\/\/|\/\/)(?!<?php\s+e\(assetVersion)[^"\']*\.css["\']/';
public function testTemplateAssetReferencesUseAssetVersion(): void
{
$this->assertAssetVersionUsed('templates');
}
public function testCorePageAssetReferencesUseAssetVersion(): void
{
$this->assertAssetVersionUsed('pages');
}
public function testModulePageAssetReferencesUseAssetVersion(): void
{
$root = $this->projectRootPath();
$modulesDir = $root . '/modules';
if (!is_dir($modulesDir)) {
self::markTestSkipped('modules/ directory missing.');
}
foreach (scandir($modulesDir) ?: [] as $entry) {
if ($entry === '.' || $entry === '..' || !is_dir($modulesDir . '/' . $entry)) {
continue;
}
foreach (['pages', 'templates'] as $subdir) {
$rel = 'modules/' . $entry . '/' . $subdir;
if (is_dir($root . '/' . $rel)) {
$this->assertAssetVersionUsed($rel);
}
}
}
}
private function assertAssetVersionUsed(string $relativeDirectory): void
{
$jsViolations = $this->findPatternMatchesInFiles($relativeDirectory, self::BARE_JS_PATTERN, ['phtml']);
$cssViolations = $this->findPatternMatchesInFiles($relativeDirectory, self::BARE_CSS_PATTERN, ['phtml']);
$violations = array_unique(array_merge($jsViolations, $cssViolations));
sort($violations);
self::assertSame(
[],
$violations,
"Asset references must use assetVersion() for cache-busting. Violations:\n" . implode("\n", $violations)
);
}
}