diff --git a/src/Utility/Asset/AssetStrategy.php b/src/Utility/Asset/AssetStrategy.php new file mode 100644 index 0000000..730fac6 --- /dev/null +++ b/src/Utility/Asset/AssetStrategy.php @@ -0,0 +1,76 @@ + for more details. + */ +namespace BEdita\WebTools\Utility\Asset; + +use Cake\Core\InstanceConfigTrait; + +/** + * Abstract base class for asset strategies. + * Every asset strategy should extend this class or implements `AssetStrategyInterface` + */ +abstract class AssetStrategy implements AssetStrategyInterface +{ + use InstanceConfigTrait; + + /** + * Default configuration. + * + * - `manifestPath` is the file path used as manifest for assets + * + * @var array + */ + protected $_defaultConfig = [ + 'manifestPath' => '', + ]; + + /** + * The assets map loaded. + * + * @var array + */ + protected $assets = []; + + /** + * Initialize an asset strategy instance. Called after the constructor. + * + * - write conf + * - load assets + * + * @param array $config The configuration for the asset strategy + */ + public function __construct(array $config = []) + { + $this->setConfig($config); + $this->loadAssets(); + } + + /** + * Load assets map. + * If no map path is passed then it uses the configured one. + * + * @param string|null $manifestPath The optional file path to use + * @return void + */ + public function loadAssets(?string $manifestPath = null): void + { + $this->assets = []; + if (empty($manifestPath)) { + $manifestPath = $this->getConfig('manifestPath'); + } + if (file_exists($manifestPath)) { + $this->assets = (array)json_decode(file_get_contents($manifestPath), true); + } + } +} diff --git a/src/Utility/Asset/AssetStrategyInterface.php b/src/Utility/Asset/AssetStrategyInterface.php new file mode 100644 index 0000000..27b8c41 --- /dev/null +++ b/src/Utility/Asset/AssetStrategyInterface.php @@ -0,0 +1,38 @@ + for more details. + */ +namespace BEdita\WebTools\Utility\Asset; + +/** + * Interface that describe an asset strategy. + */ +interface AssetStrategyInterface +{ + /** + * Retrieve the asset corresponding to the name passed. + * + * @param string $name The name used to looking for the asset + * @param string|null $extension Optional asset extension as 'js' or 'css' + * @return string|array + */ + public function get(string $name, ?string $extension = null); + + /** + * Load assets map optionally using a file path. + * + * @param string|null $path The optional file path + * @return void + */ + public function loadAssets(?string $path = null): void; +} diff --git a/src/Utility/Asset/Strategy/EntrypointsStrategy.php b/src/Utility/Asset/Strategy/EntrypointsStrategy.php new file mode 100644 index 0000000..41914d5 --- /dev/null +++ b/src/Utility/Asset/Strategy/EntrypointsStrategy.php @@ -0,0 +1,69 @@ + for more details. + */ + namespace BEdita\WebTools\Utility\Asset\Strategy; + +use BEdita\WebTools\Utility\Asset\AssetStrategy; +use Cake\Utility\Hash; + +/** + * Entrypoints asset strategy. + * This strategy is based on map produced by Webpack Encore and expects a JSON assets map like + * + * ``` + * { + * "entrypoints": { + * "app": { + * "js": [ + * "/build/runtime.f011bcb1.js", + * "/build/0.54651780.js", + * "/build/app.82269f26.js" + * ] + * }, + * "style": { + * "js": [ + * "/build/runtime.f011bcb1.js" + * ], + * "css": [ + * "/build/style.12c5249c.css" + * ] + * } + * } + * } + * ``` + * + * @see https://symfony.com/doc/current/frontend.html + */ +class EntrypointsStrategy extends AssetStrategy +{ + /** + * {@inheritDoc} + */ + protected $_defaultConfig = [ + 'manifestPath' => WWW_ROOT . 'build' . DS . 'entrypoints.json', + ]; + + /** + * {@inheritDoc} + */ + public function get(string $name, ?string $extension = null) + { + $path = sprintf('entrypoints.%s', $name); + if (!empty($extension)) { + $path .= sprintf('.%s', $extension); + } + + return Hash::get($this->assets, $path); + } +} diff --git a/src/Utility/Asset/Strategy/RevManifestStrategy.php b/src/Utility/Asset/Strategy/RevManifestStrategy.php new file mode 100644 index 0000000..670cd11 --- /dev/null +++ b/src/Utility/Asset/Strategy/RevManifestStrategy.php @@ -0,0 +1,54 @@ + for more details. + */ +namespace BEdita\WebTools\Utility\Asset\Strategy; + +use BEdita\WebTools\Utility\Asset\AssetStrategy; + +/** + * RevManifest asset strategy. + * This strategy expects a JSON assets map like + * + * ``` + * { + * "app.js": "app.13gdr5.js", + * "style.css: "style.lgcf6a.js" + * } + * ``` + */ +class RevManifestStrategy extends AssetStrategy +{ + /** + * {@inheritDoc} + */ + protected $_defaultConfig = [ + 'manifestPath' => WWW_ROOT . 'rev-manifest.json', + ]; + + /** + * {@inheritDoc} + */ + public function get(string $name, ?string $extension = null) + { + if (!empty($extension)) { + $name .= sprintf('.%s', $extension); + } + + if (empty($this->assets[$name])) { + return null; + } + + return $this->assets[$name]; + } +} diff --git a/src/Utility/AssetsRevisions.php b/src/Utility/AssetsRevisions.php index 316f2be..4199eb8 100644 --- a/src/Utility/AssetsRevisions.php +++ b/src/Utility/AssetsRevisions.php @@ -12,77 +12,109 @@ * * See LICENSE.LGPL or for more details. */ - namespace BEdita\WebTools\Utility; +use BEdita\WebTools\Utility\Asset\AssetStrategyInterface; + /** * Utility class to handle asset names with revisions/signatures. * - * Rev manifest file default path is `config/rev-manifest.json` - * Other file paths may be used via `loadManifest()` + * It can use different strategies to search assets. */ class AssetsRevisions { /** - * Array having asset names as keys and revved asset names as values + * The asset strategy adopted. * - * @var array + * @var \BEdita\WebTools\Utility\Asset\AssetStrategyInterface */ - protected static $assets = null; + protected static $strategy = null; /** - * Load revision manifest JSON. + * Set an asset strategy to be used. * - * @param string $path Manifest file path + * @param \BEdita\WebTools\Utility\Asset\AssetStrategyInterface $strategy The asset strategy to use * @return void */ - public static function loadManifest(?string $path = null): void + public static function setStrategy(AssetStrategyInterface $strategy): void { - static::$assets = []; - if (empty($path)) { - $path = CONFIG . 'rev-manifest.json'; - } - if (file_exists($path)) { - static::$assets = (array)json_decode(file_get_contents($path), true); - } + static::$strategy = $strategy; } /** - * Retrieve `revved` asset name if found in manifest or return canonical asset name otherwise + * Get the current asset strategy adopted. * - * @param string $name Canonical asset name (un-revved) - * @param string $extension Optional extension to use to search asset, like '.js' or '.css' - * @return string + * @return \BEdita\WebTools\Utility\Asset\AssetStrategyInterface|null */ - public static function get(string $name, ?string $extension = null): string + public static function getStrategy(): ?AssetStrategyInterface { - if (static::$assets === null) { - static::loadManifest(); - } + return static::$strategy; + } - if (!empty(static::$assets[$name])) { - return (string)static::$assets[$name]; + /** + * Clear asset strategy. + * + * @return void + */ + public static function clearStrategy(): void + { + static::$strategy = null; + } + + /** + * Retrieve asset name or an array of assets . + * Return canonical asset name if no assets was found. + * + * @param string $name Canonical asset name + * @param string $extension Optional extension to use to search asset, like 'js' or 'css' + * @return string|array + */ + public static function get(string $name, ?string $extension = null) + { + $strategy = static::getStrategy(); + if ($strategy === null) { + return $name; } - if (!empty($extension) && !empty(static::$assets[$name . $extension])) { - return (string)static::$assets[$name . $extension]; + + $asset = $strategy->get($name, $extension); + if (!empty($asset)) { + return $asset; } return $name; } /** - * Retrieve `revved` asset names array via ::get() call + * Retrieve asset names array via ::get() call * - * @param array $names Canonical asset names (un-revved) - * @param string $extension Optional extension to use to search asset, like '.js' or '.css' + * @param array $names Canonical asset names + * @param string $extension Optional extension to use to search asset, like 'js' or 'css' * @return array */ public static function getMulti(array $names, ?string $extension = null): array { - foreach ($names as $k => $val) { - $names[$k] = static::get($val, $extension); + $assets = []; + foreach ($names as $val) { + $assets = array_merge($assets, (array)static::get($val, $extension)); + } + + return $assets; + } + + /** + * Load assets for adopted asset strategy. + * + * @param string $path Manifest file path + * @return void + * @throws \LogicException If startegy is not defined + */ + public static function loadManifest(?string $path = null): void + { + $strategy = static::getStrategy(); + if ($strategy === null) { + throw new \LogicException('Missing asset strategy'); } - return $names; + $strategy->loadAssets($path); } } diff --git a/src/View/Helper/HtmlHelper.php b/src/View/Helper/HtmlHelper.php index f1722a9..5d09efc 100644 --- a/src/View/Helper/HtmlHelper.php +++ b/src/View/Helper/HtmlHelper.php @@ -358,9 +358,9 @@ public function getMeta(array $data, string $field, $defaultVal = null) public function script($url, array $options = []): ?string { if (is_array($url)) { - $url = AssetsRevisions::getMulti($url, '.js'); + $url = AssetsRevisions::getMulti($url, 'js'); } else { - $url = AssetsRevisions::get($url, '.js'); + $url = AssetsRevisions::get($url, 'js'); } return parent::script($url, $options); @@ -374,11 +374,29 @@ public function script($url, array $options = []): ?string public function css($url, array $options = []): ?string { if (is_array($url)) { - $url = AssetsRevisions::getMulti($url, '.css'); + $url = AssetsRevisions::getMulti($url, 'css'); } else { - $url = AssetsRevisions::get($url, '.css'); + $url = AssetsRevisions::get($url, 'css'); } return parent::css($url, $options); } + + /** + * Creates link elements for CSS stylesheets and JS by asset name. + * + * @param string $name The asset name + * @param array $options The options to apply + * @return string|null + */ + public function assets($name, array $options = []): ?string + { + $cssOutput = $this->css($name, $options); + $jsOutput = $this->script($name, $options); + if (empty($cssOutput)) { + return $jsOutput; + } + + return $cssOutput . (string)$jsOutput; + } } diff --git a/tests/TestCase/Utility/Asset/AssetStrategyTest.php b/tests/TestCase/Utility/Asset/AssetStrategyTest.php new file mode 100644 index 0000000..ab16d8a --- /dev/null +++ b/tests/TestCase/Utility/Asset/AssetStrategyTest.php @@ -0,0 +1,95 @@ + for more details. + */ +namespace BEdita\WebTools\Test\TestCase\Utility\Asset\Strategy; + +use BEdita\WebTools\Utility\Asset\AssetStrategy; +use Cake\TestSuite\TestCase; + +/** + * {@see \BEdita\WebTools\Utility\Asset\AssetStrategy} Test Case + * + * @coversDefaultClass \BEdita\WebTools\Utility\Asset\AssetStrategy + */ +class AssetStrategyTest extends TestCase +{ + /** + * Return an instance of anonymous class that extends AssetStrategy + * + * @param array $config The configuration to use + * @return AssetStrategy + */ + protected function getInstance(array $config = []): AssetStrategy + { + return new class ($config) extends AssetStrategy { + public function get(string $name, ?string $extension = null) + { + return $this->assets; + } + }; + } + + /** + * Data provider for `testManifestPath()` + * + * @return array + */ + public function manifestPathProvider(): array + { + return [ + 'default' => [ + '', + [], + ], + 'custom' => [ + '/manifest/custom/path.json', + [ + 'manifestPath' => '/manifest/custom/path.json', + ], + ], + ]; + } + + /** + * Test that manifest path is well configured. + * + * @param string $expected The expected path + * @param array $config The configuration used + * @return void + * + * @dataProvider manifestPathProvider() + * @covers ::__construct() + */ + public function testManifestPath(string $expected, array $config): void + { + $strategy = $this->getInstance($config); + + static::assertEquals($expected, $strategy->getConfig('manifestPath')); + } + + /** + * Test `loadASsets()` + * + * @return void + * + * @covers ::loadAssets() + */ + public function testLoadAssets(): void + { + $path = WWW_ROOT . 'custom-manifest.json'; + $expected = json_decode(file_get_contents($path), true); + $strategy = $this->getInstance(['manifestPath' => $path]); + static::assertEquals($expected, $strategy->get('all')); + } +} diff --git a/tests/TestCase/Utility/Asset/Strategy/EntrypointsStrategyTest.php b/tests/TestCase/Utility/Asset/Strategy/EntrypointsStrategyTest.php new file mode 100644 index 0000000..74eb587 --- /dev/null +++ b/tests/TestCase/Utility/Asset/Strategy/EntrypointsStrategyTest.php @@ -0,0 +1,78 @@ + for more details. + */ +namespace BEdita\WebTools\Test\TestCase\Utility\Asset\Strategy; + +use BEdita\WebTools\Utility\Asset\Strategy\EntrypointsStrategy; +use Cake\TestSuite\TestCase; + +/** + * {@see \BEdita\WebTools\Utility\Asset\Strategy\EntrypointsStrategy} Test Case + * + * @coversDefaultClass \BEdita\WebTools\Utility\Asset\Strategy\EntrypointsStrategy + */ +class EntrypointsStrategyTest extends TestCase +{ + /** + * Data provider for `testGet()` + * + * @return array + */ + public function getProvider(): array + { + return [ + 'not found' => [ + null, + 'gustavo', + ], + 'all assets for entrypoint' => [ + [ + 'js' => [ + '/build/runtime.f011bcb1.js', + ], + 'css' => [ + '/build/style.12c5249c.css', + ], + ], + 'style', + ], + 'all js assets for entrypoint' => [ + [ + '/build/runtime.f011bcb1.js', + '/build/0.54651780.js', + '/build/app.82269f26.js', + ], + 'app', + 'js', + ], + ]; + } + + /** + * Test that get asset name works as expected. + * + * @param string $expected The expected path + * @param array $name The configuration used + * @return void + * + * @dataProvider getProvider() + * @covers ::get() + */ + public function testGet(?array $expected, string $name, ?string $extension = null): void + { + $strategy = new EntrypointsStrategy(['manifestPath' => WWW_ROOT . 'entrypoints.json']); + + static::assertEquals($expected, $strategy->get($name, $extension)); + } +} diff --git a/tests/TestCase/Utility/Asset/Strategy/RevManifestStrategyTest.php b/tests/TestCase/Utility/Asset/Strategy/RevManifestStrategyTest.php new file mode 100644 index 0000000..67e5b7a --- /dev/null +++ b/tests/TestCase/Utility/Asset/Strategy/RevManifestStrategyTest.php @@ -0,0 +1,71 @@ + for more details. + */ +namespace BEdita\WebTools\Test\TestCase\Utility\Asset\Strategy; + +use BEdita\WebTools\Utility\Asset\Strategy\RevManifestStrategy; +use Cake\TestSuite\TestCase; + +/** + * {@see \BEdita\WebTools\Utility\Asset\Strategy\RevManifestStrategy} Test Case + * + * @coversDefaultClass \BEdita\WebTools\Utility\Asset\Strategy\RevManifestStrategy + */ +class RevManifestStrategyTest extends TestCase +{ + /** + * Data provider for `testGet()` + * + * @return array + */ + public function getProvider(): array + { + return [ + 'name' => [ + 'support.xyz123.js', + 'support', + ], + 'name with extension' => [ + 'script-622a2cc4f5.js', + 'script.js', + ], + 'name and extension' => [ + 'script-622a2cc4f5.js', + 'script', + 'js', + ], + 'not found' => [ + null, + 'gustavo', + ], + ]; + } + + /** + * Test that get asset name works as expected. + * + * @param string $expected The expected path + * @param array $name The configuration used + * @return void + * + * @dataProvider getProvider() + * @covers ::get() + */ + public function testGet(?string $expected, string $name, ?string $extension = null): void + { + $strategy = new RevManifestStrategy(); + + static::assertEquals($expected, $strategy->get($name, $extension)); + } +} diff --git a/tests/TestCase/Utility/AssetsRevisionsTest.php b/tests/TestCase/Utility/AssetsRevisionsTest.php index 95a61a7..04d08cd 100644 --- a/tests/TestCase/Utility/AssetsRevisionsTest.php +++ b/tests/TestCase/Utility/AssetsRevisionsTest.php @@ -3,7 +3,7 @@ /** * BEdita, API-first content management framework - * Copyright 2019 ChannelWeb Srl, Chialab Srl + * Copyright 2020 ChannelWeb Srl, Chialab Srl * * This file is part of BEdita: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -12,8 +12,10 @@ * * See LICENSE.LGPL or for more details. */ -namespace BEdita\WebTools\Test\TestCase\View\Helper; +namespace BEdita\WebTools\Test\TestCase\Utility; +use BEdita\WebTools\Utility\Asset\Strategy\EntrypointsStrategy; +use BEdita\WebTools\Utility\Asset\Strategy\RevManifestStrategy; use BEdita\WebTools\Utility\AssetsRevisions; use Cake\TestSuite\TestCase; @@ -24,6 +26,40 @@ */ class AssetsRevisionsTest extends TestCase { + /** + * {@inheritDoc} + */ + public function setUp(): void + { + AssetsRevisions::setStrategy(new RevManifestStrategy()); + } + + /** + * {@inheritDoc} + */ + public function tearDown(): void + { + AssetsRevisions::clearStrategy(); + } + + /** + * Test set, get and reset strategy + * + * @return void + * + * @covers ::setStrategy() + * @covers ::getStrategy() + * @covers ::clearStrategy() + */ + public function testStrategy(): void + { + AssetsRevisions::setStrategy(new EntrypointsStrategy()); + static::assertInstanceOf(EntrypointsStrategy::class, AssetsRevisions::getStrategy()); + + AssetsRevisions::clearStrategy(); + static::assertNull(AssetsRevisions::getStrategy()); + } + /** * Data provider for `testGet` test case. * @@ -43,26 +79,26 @@ public function getProvider(): array 'extension' => [ 'style-b7c54b4c5a.css', 'style', - '.css', + 'css', ], 'extension missing' => [ 'script', 'script', - '.css', + 'css', ], ]; } /** - * Test `get` method - * - * @dataProvider getProvider() - * @covers ::get() + * Test `get` method. * * @param string $expected The expected result * @param string $name The asset name * @param string $extension The asset extension * @return void + * + * @dataProvider getProvider() + * @covers ::get() */ public function testGet(string $expected, string $name, ?string $extension = null): void { @@ -70,11 +106,26 @@ public function testGet(string $expected, string $name, ?string $extension = nul static::assertEquals($expected, $result); } + /** + * Test that `get()` method returns the passed asset name when no strategy was set. + * + * @return void + * + * @covers ::get() + */ + public function testGetWithoutStrategy(): void + { + AssetsRevisions::clearStrategy(); + $name = 'app'; + static::assertEquals($name, AssetsRevisions::get($name)); + } + /** * Test `getMulti` method * - * @covers ::getMulti() * @return void + * + * @covers ::getMulti() */ public function testGetMulti(): void { @@ -83,7 +134,7 @@ public function testGetMulti(): void 'about', ]; - $result = AssetsRevisions::getMulti(['script', 'about'], '.js'); + $result = AssetsRevisions::getMulti(['script', 'about'], 'js'); static::assertEquals($expected, $result); } @@ -92,6 +143,8 @@ public function testGetMulti(): void * * @covers ::loadManifest() * @return void + * + * @covers ::loadManifest() */ public function testLoadManifest() { @@ -107,4 +160,21 @@ public function testLoadManifest() $result = AssetsRevisions::get('script.js'); static::assertEquals('script-622a2cc4f5.js', $result); } + + /** + * Test that an exception is rised trying to load manifest + * without an asset strategy set. + * + * @return void + * @expectException \LogicException + * + * @covers ::loadManifest() + */ + public function testLoadManifestWithoutStrategy(): void + { + $this->expectException(\LogicException::class); + + AssetsRevisions::clearStrategy(); + AssetsRevisions::loadManifest(); + } } diff --git a/tests/TestCase/View/Helper/AssetHelperTest.php b/tests/TestCase/View/Helper/AssetHelperTest.php index 10e7965..9f3f815 100644 --- a/tests/TestCase/View/Helper/AssetHelperTest.php +++ b/tests/TestCase/View/Helper/AssetHelperTest.php @@ -14,6 +14,8 @@ */ namespace BEdita\WebTools\Test\TestCase\View\Helper; +use BEdita\WebTools\Utility\Asset\Strategy\RevManifestStrategy; +use BEdita\WebTools\Utility\AssetsRevisions; use BEdita\WebTools\View\Helper\AssetHelper; use Cake\TestSuite\TestCase; use Cake\View\View; @@ -34,6 +36,7 @@ class AssetHelperTest extends TestCase */ public function testGet(): void { + AssetsRevisions::setStrategy(new RevManifestStrategy()); $Asset = new AssetHelper(new View()); $result = $Asset->get('script.js'); static::assertEquals('script-622a2cc4f5.js', $result); diff --git a/tests/TestCase/View/Helper/HtmlHelperTest.php b/tests/TestCase/View/Helper/HtmlHelperTest.php index 1dbbcd5..cc0b033 100644 --- a/tests/TestCase/View/Helper/HtmlHelperTest.php +++ b/tests/TestCase/View/Helper/HtmlHelperTest.php @@ -14,6 +14,10 @@ */ namespace BEdita\WebTools\Test\TestCase\View\Helper; +use BEdita\WebTools\Utility\Asset\AssetStrategyInterface; +use BEdita\WebTools\Utility\Asset\Strategy\EntrypointsStrategy; +use BEdita\WebTools\Utility\Asset\Strategy\RevManifestStrategy; +use BEdita\WebTools\Utility\AssetsRevisions; use BEdita\WebTools\View\Helper\HtmlHelper; use Cake\Http\ServerRequest; use Cake\TestSuite\TestCase; @@ -50,6 +54,7 @@ public function setUp(): void public function tearDown(): void { unset($this->Html); + AssetsRevisions::clearStrategy(); parent::tearDown(); } @@ -496,18 +501,36 @@ public function scriptProvider(): array { return [ 'simple' => [ - '', + ['script' => ['src' => '/script-622a2cc4f5.js']], 'script', + new RevManifestStrategy(), ], 'not found' => [ - '', + ['script' => ['src' => '/functions.js']], 'functions.js', + new RevManifestStrategy(), ], 'multi' => [ - '' . - "\n\t" . - '', + [ + ['script' => ['src' => '/script-622a2cc4f5.js']], + '/script', + ['script' => ['src' => '/page-1x4f92530c.js']], + '/script', + ], ['script', 'page'], + new RevManifestStrategy(), + ], + 'entrypoint app' => [ + [ + ['script' => ['src' => '/build/runtime.f011bcb1.js']], + '/script', + ['script' => ['src' => '/build/0.54651780.js']], + '/script', + ['script' => ['src' => '/build/app.82269f26.js']], + '/script', + ], + 'app', + new EntrypointsStrategy(['manifestPath' => WWW_ROOT . 'entrypoints.json']), ], ]; } @@ -515,17 +538,19 @@ public function scriptProvider(): array /** * Test `script` method * - * @dataProvider scriptProvider() - * @covers ::script() - * - * @param string|string[] $expected The expected result + * @param array $expected The expected result * @param string|string[] $name The asset name + * @param \BEdita\WebTools\Utility\Asset\AssetStrategyInterface $strategy The asset strategy to adopt * @return void + * + * @dataProvider scriptProvider() + * @covers ::script() */ - public function testScript($expected, $name): void + public function testScript($expected, $name, AssetStrategyInterface $strategy): void { + AssetsRevisions::setStrategy($strategy); $result = $this->Html->script($name); - static::assertEquals($expected, trim($result)); + $this->assertHtml($expected, $result); } /** @@ -537,18 +562,52 @@ public function cssProvider(): array { return [ 'simple' => [ - '', + [ + 'link' => [ + 'rel' => 'stylesheet', + 'href' => '/style-b7c54b4c5a.css', + ], + ], 'style', + new RevManifestStrategy(), ], 'not found' => [ - '', + [ + 'link' => [ + 'rel' => 'stylesheet', + 'href' => '/home.css', + ], + ], 'home.css', + new RevManifestStrategy(), ], 'multi' => [ - '' . - "\n\t" . - '', + [ + [ + 'link' => [ + 'rel' => 'stylesheet', + 'href' => '/style-b7c54b4c5a.css', + ], + ], + [ + 'link' => [ + 'rel' => 'stylesheet', + 'href' => '/page.css', + ], + ], + ], ['style', 'page'], + new RevManifestStrategy(), + ], + 'entrypoint style' => [ + [ + 'link' => [ + 'rel' => 'stylesheet', + 'href' => '/build/style.12c5249c.css', + ], + ], + 'style', + new EntrypointsStrategy(['manifestPath' => WWW_ROOT . 'entrypoints.json']), ], ]; } @@ -556,16 +615,73 @@ public function cssProvider(): array /** * Test `css` method * + * @param array $expected The expected result + * @param string|string[] $name The asset name + * @param \BEdita\WebTools\Utility\Asset\AssetStrategyInterface $strategy The asset strategy to adopt + * @return void + * * @dataProvider cssProvider() * @covers ::css() + */ + public function testCss($expected, $name, AssetStrategyInterface $strategy): void + { + AssetsRevisions::setStrategy($strategy); + $result = $this->Html->css($name); + $this->assertHtml($expected, $result); + } + + /** + * Data provider for `testAssets` test case. * - * @param string|string[] $expected The expected result + * @return array + */ + public function assetsProvider(): array + { + return [ + 'css found and js fallback' => [ + [ + 'link' => [ + 'rel' => 'stylesheet', + 'href' => '/style-b7c54b4c5a.css', + ], + 'script' => [ + 'src' => '/style.js', + ], + ], + 'style', + new RevManifestStrategy(), + ], + 'entrypoint style' => [ + [ + 'link' => [ + 'rel' => 'stylesheet', + 'href' => '/build/style.12c5249c.css', + ], + 'script' => [ + 'src' => '/build/runtime.f011bcb1.js', + ], + ], + 'style', + new EntrypointsStrategy(['manifestPath' => WWW_ROOT . 'entrypoints.json']), + ], + ]; + } + + /** + * Test `asset` method. + * + * @param array $expected The expected result * @param string|string[] $name The asset name + * @param \BEdita\WebTools\Utility\Asset\AssetStrategyInterface $strategy The asset strategy to adopt * @return void + * + * @dataProvider assetsProvider() + * @covers ::assets() */ - public function testCss($expected, $name): void + public function testAssets($expected, $name, AssetStrategyInterface $strategy): void { - $result = $this->Html->css($name); - static::assertEquals($expected, trim($result)); + AssetsRevisions::setStrategy($strategy); + $result = $this->Html->assets($name); + $this->assertHtml($expected, $result); } } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 055f43c..9a085ac 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -58,6 +58,7 @@ define('LOGS', TMP . 'logs' . DS); define('CACHE', TMP . 'cache' . DS); define('CONFIG', ROOT . DS . 'config' . DS); +define('WWW_ROOT', ROOT . DS . 'webroot' . DS); define('CAKE_CORE_INCLUDE_PATH', ROOT); define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS); diff --git a/tests/test_app/webroot/custom-manifest.json b/tests/test_app/webroot/custom-manifest.json new file mode 100644 index 0000000..8a22b15 --- /dev/null +++ b/tests/test_app/webroot/custom-manifest.json @@ -0,0 +1,4 @@ +{ + "gustavo.js": "build/gustavo.js", + "supporto.css": "build/supporto.css" +} diff --git a/tests/test_app/webroot/entrypoints.json b/tests/test_app/webroot/entrypoints.json new file mode 100644 index 0000000..651960d --- /dev/null +++ b/tests/test_app/webroot/entrypoints.json @@ -0,0 +1,19 @@ +{ + "entrypoints": { + "app": { + "js": [ + "/build/runtime.f011bcb1.js", + "/build/0.54651780.js", + "/build/app.82269f26.js" + ] + }, + "style": { + "js": [ + "/build/runtime.f011bcb1.js" + ], + "css": [ + "/build/style.12c5249c.css" + ] + } + } +} \ No newline at end of file diff --git a/tests/test_app/webroot/rev-manifest.json b/tests/test_app/webroot/rev-manifest.json new file mode 100644 index 0000000..4631d5c --- /dev/null +++ b/tests/test_app/webroot/rev-manifest.json @@ -0,0 +1,6 @@ +{ + "script.js": "script-622a2cc4f5.js", + "page.js": "page-1x4f92530c.js", + "style.css": "style-b7c54b4c5a.css", + "support": "support.xyz123.js" +}