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>
75 lines
2.5 KiB
PHP
75 lines
2.5 KiB
PHP
<?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)
|
|
);
|
|
}
|
|
}
|